Sembra fare la differenza se si fa riferimento a this.type
dall'interno di un tratto o dall'ambito di creazione dell'oggetto, con risultati sorprendenti.Equivalenze e non equivalenze sorprendenti per questo.tipo
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
ecco l'output:
false // As expected: the singleton types of two objects are different.
Trait constructor: [email protected]295
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.
Quindi, ci sono due oggetti distinti, ma a quanto pare ogni sta ottenendo un tag di tipo equivalente per la sua this.type
, che non è equivalente alla .type
dell'oggetto come visto da un ambito di chiusura.
Si tratta di un bug del compilatore o, in caso contrario, potresti spiegare perché questo comportamento ha senso?
(sto correndo Scala 2.11.2. Ho provato con un self
alias per this
, con lo stesso risultato.)
Per quello che vale, quando ho esegui il tuo codice ottengo un errore interno del compilatore. Quindi, un bug del compilatore non sembra troppo improbabile. Come un altro modo di sperimentare, un modo più diretto per ottenere un'idea simile è di avere un metodo che restituisca il tipo di un oggetto locale. – Owen
@Owen Sulla base della nostra conversazione di seguito, della mia ricerca attraverso le specifiche e di una ricerca nel database dei problemi, sono andato avanti e ho postato il mio [primo bug di Scala] (https://issues.scala-lang.org/browse/SI -9439). Spero che non sia un duplicato o in realtà non sia un bug! –
La mia attuale comprensione (basandosi sui commenti di Owen e Jason Zaugg): ogni tipo dipendente dal percorso ha un "prefisso" che indica dove trovare l'oggetto nel suo ambito. Il controllo di equivalenza dei tipi esamina il prefisso, non l'oggetto stesso (che esiste solo in fase di esecuzione e potrebbe non essere mai creato). Quindi, all'interno di 'Trait',' this.type' ha il prefisso 'Trait', risultando nel tipo' Trait.this.type'-per tutte le istanze. 'Instance1.type' ha un prefisso che dice che l'oggetto è definito nell'ambito di primo livello, con il nome' Instance1', risultando in tipo 'Instance1.type'-diverso da dentro 'Trait'. –