2015-08-18 23 views
6

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.)

+0

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

+0

@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! –

+0

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'. –

risposta

2

I seguenti programma stampa falsa e quindi vera. A mio avviso, non ci dovrebbe essere alcuna differenza sostanziale tra questi due casi (anche se questo è davvero più di un parere, non posso davvero dire se c'è una ragione o meno):

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

Penso che poiché i due oggetti creati dalle chiamate a 'foo' sono diversi, è corretto che i loro tag di tipo Singleton siano diversi. La creazione di un oggetto viola la trasparenza referenziale o lo fa? Forse questa è la chiave di ciò che sto chiedendo. –

+0

La [specifica dice] (http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#object-definitions) che una definizione di oggetto definisce un singolo oggetto di una nuova classe._ Finora, non ho trovato nulla per indicare se una definizione di un singolo oggetto all'interno di una definizione di funzione dovrebbe definire un oggetto o tanti oggetti quante volte viene chiamata la funzione. Ma sembra che i due 'Instance's, con definizioni separate, dovrebbero avere tipi separati. –

+0

@BenKovitz Passare '-Yprint: typer' potrebbe essere informativo qui ... ridurrà le definizioni degli oggetti in una definizione di classe e una nuova creazione di istanza, in modo da poter vedere esattamente quante istanze sono state create. – Owen