6

Es scheint einen Unterschied zu machen, ob Sie this.type aus einer Eigenschaft oder aus dem Bereich, in dem das Objekt erstellt wird, beziehen, mit überraschenden Ergebnissen.Überraschende Äquivalenzen und Nicht-Äquivalenzen bezüglich this.type

import scala.reflect.runtime.universe._ 

trait Trait { 
    val ttag = typeOf[this.type] 
    println(s"Trait constructor: $this") 
} 

object Instance1 extends Trait 

object Instance2 extends Trait 

println(typeOf[Instance1.type] =:= typeOf[Instance2.type]) // Should be false 
println(Instance1.ttag =:= Instance2.ttag)     // Should be false 
println(Instance1.ttag =:= typeOf[Instance1.type])   // Should be true 

Hier ist der Ausgang:

false // As expected: the singleton types of two objects are different. 
Trait constructor: [email protected] 
Trait constructor: [email protected] 
true  // But the this.type tags are equivalent 
false // and the this.type tag is not equivalent to the singleton type. 

So gibt es zwei verschiedene Objekte, aber anscheinend ist jeweils einen äquivalenten Typ-Tag bekommt für seine this.type, die die .type des Objektes nicht gleichwertig ist von einem umschließenden Umfang gesehen.

Ist das ein Compiler-Bug oder, wenn nicht, könnten Sie erklären, warum dieses Verhalten sinnvoll ist?

(Ich bin mit Scala 2.11.2. Ich habe es versucht, mit einem self alias für this, mit dem gleichen Ergebnis.)

+0

Für das, was es wert ist, wenn ich starte deinen Code Ich erhalte einen internen Compilerfehler. Ein Compiler-Fehler scheint also nicht unwahrscheinlich. Eine weitere Möglichkeit, zu experimentieren, besteht darin, eine Methode zu verwenden, die den Typ eines lokalen Objekts zurückgibt. – Owen

+0

@Owen Basierend auf unserer Konversation unten, meiner Suche durch die Spezifikation und einer Suche in der Problemdatenbank, ging ich weiter und postete meinen [ersten Scala-Fehler] (https://issues.scala-lang.org/browse/SI -9439). Ich hoffe es ist kein Duplikat oder eigentlich kein Bug! –

+0

Mein aktuelles Verständnis (aufbauend auf Owens und Jason Zauggs Kommentaren): Jeder pfadabhängige Typ hat ein "Präfix", das angibt, wo das Objekt in seinem Umfang zu finden ist. Die Typäquivalenzprüfung prüft das Präfix, nicht das Objekt selbst (das nur zur Laufzeit existiert und möglicherweise nie erstellt wird). Innerhalb 'Trait' hat' this.type 'das Präfix 'Trait', was zum Typ' Trait.this.type' führt - für alle Instanzen. 'Instance1.type' hat ein Präfix, das besagt, dass das Objekt im Top-Level-Bereich definiert ist, mit dem Namen' Instance1', was zum Typ 'Instance1.type' führt - anders als innerhalb von' Trait'. –

Antwort

2

Das folgende Programm druckt falsch und dann wahr. Meiner Meinung nach, sollte es keinen wesentlichen Unterschied zwischen diesen beiden Fällen (wenn auch das ist wirklich eher eine Meinung, ich nicht wirklich sagen kann, ob es einen Grund gibt oder nicht):

import scala.reflect.runtime.universe._ 

object Test2 extends App { 
    def foo(): Type = { 
    object a 
    typeOf[a.type] 
    } 

    println(foo() =:= foo()) // false 

    trait Trait { 
    val ttag = typeOf[this.type] 
    } 

    object Instance1 extends Trait 

    object Instance2 extends Trait 

    println(Instance1.ttag =:= Instance2.ttag) // true 
} 
+0

Ich denke, dass, da die zwei Objekte, die durch die Aufrufe von 'foo' erstellt wurden, unterschiedlich sind, es korrekt ist, dass ihre Singleton-Typ-Typ-Tags unterschiedlich sind. Das Erstellen eines Objekts verletzt referentielle Transparenz - oder? Vielleicht ist das der Schlüssel zu dem, was ich frage. –

+0

Die [Spezifikation sagt] (http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#object-definitions), dass eine Objektdefinition ein einzelnes Objekt definiert a _new class._ Bisher habe ich nichts gefunden, um anzugeben, ob eine einzelne Objektdefinition innerhalb einer Funktionsdefinition ein Objekt oder so viele Objekte definieren soll, wie die Funktion aufgerufen wird. Aber es scheint, dass die zwei Instanzen mit getrennten Definitionen getrennte Typen haben sollten. –

+0

@BenKovitz Das Verarbeiten von '-Yprint: type' könnte hier informativ sein ... es wird Objektdefinitionen in eine Klassendefinition und eine neue Instanzerstellung entwerfen, so dass Sie genau sehen können, wie viele Instanzen erstellt werden. – Owen

Verwandte Themen