2009-09-08 9 views
16

In Scala posso fare questo:Scala sovrascrivendo una definizione non astratta con una var

trait SomeTrait { 
    protected def foo: String 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" 
} 

ma non posso fare la stessa cosa in cui ho fornire una definizione di default per foo

trait SomeTrait { 
    protected def foo: String = "World" 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" //complains about lack of override modifier 

    override protected var foo = "Hello" //complains "method foo_ overrides nothing" 
} 

Perché non posso farlo?

EDIT: Dopo una conversazione sulla Scala mailing list degli utenti, ho raised this in trac

risposta

19

In Scala, quando si scrive un var foo, il compilatore Scala genera automaticamente un setter (chiamato foo_=) e un getter (chiamato foo) per esso e imposta il campo come privato (lo vedrete come privato se decompilate una classe con campi Scala "pubblici" con javap). Questo è ciò che significa il metodo 'method foo_ = overrides nothing'. Nel tuo tratto non hai definito un metodo foo_=, e per un field setter e getter pubblici sempre venire in coppia.

Se non si fornisce un valore predefinito nel tratto (cioè astratto metodo), quindi la parola chiave override non è necessario. Pertanto, nel tuo primo esempio, il getter sovrascrive il metodo astratto e il setter ... è proprio lì. Il compilatore non si lamenta. Tuttavia, quando fornisci un'implementazione effettiva del metodo nel tratto, devi scrivere specificamente la parola chiave override quando esegui l'override. Quando si scrive protected var foo, non è stata specificata la parola chiave per il getter e quando si scrive override protected var foo, è stato anche indicato al compilatore che il metodo foo_= deve essere sovrascritto, ma il tratto non ha tale metodo.

Inoltre, logicamente non è possibile sovrascrivere uno def con un var (considerando una visione rigorosa dell'override, come nel paragrafo precedente). A def è logicamente una funzione (gli dai un input, produce un output). Un var è simile a una funzione no-arg, ma supporta anche l'impostazione del suo valore su qualcos'altro, un'operazione che non è supportata da una funzione. Invece, se dovessi cambiarlo in uno val, sarebbe OK. È come una funzione che produce sempre lo stesso risultato (memorizzato nella cache).

Se si vuole avere un comportamento simile ad un var si potrebbe fare qualcosa di simile (avendo setter esplicito e getter):

class Wibble extends SomeTrait { 
    private var bar = "Hello" 
    override protected def foo = bar 
    protected def foo_=(v: String) { bar = v} 
} 

Ora si può fare qualsiasi cosa si potrebbe fare con un var :).

val x = new Wibble 
println(x.foo) // yields "Hello" 
x.foo = "Hello again" 
println(x.foo) // yields "Hello again" 
+0

Mi dispiace - ho fatto un errore - il metodo del tratto originale avrebbe dovuto essere protetto anche. Non sono sicuro di essere d'accordo con te sul fatto che non sia logicamente possibile sovrascrivere un 'def' con un' var'. Tutto il mio 'def' sta dicendo è che mi aspetto che ci sia un accessore chiamato' foo' che restituisce una stringa - dichiarando che 'var' è un'implementazione di questo –

+0

Penso di essere d'accordo con te. Stavo pensando di scavalcare come una nozione più severa quando ho scritto la risposta. Modificherò la risposta e fornirò una soluzione praticabile :). –

+0

È un peccato che non ci sia una sintassi di 'override def as var' –

Problemi correlati