2011-09-06 11 views
12

Per che cosa posso usare il modificatore private final in Scala per?Uso del modificatore finale privato di Scala?

dato il codice qui sotto:

1| class A { def callFoo = foo; private final def foo = "bar of A" } 
2| class B extends A { private final def foo = "bar of B"} 
3| println((new A()).callFoo) 
4| println((new B()).callFoo) 

Linea 3 e 4 stampe:

1| bar of A 
2| bar of A 

E 'comprensibile il motivo per cui la linea 2 non stampa bar of B perché ci sono in realtà due foo definizioni e questi ultimi in B non sovrascrive il primo in A. Altrimenti Scala richiederebbe il override - invece del modificatore final.

Quindi perché Scala non ha semplicemente vietato la combinazione dei modificatori private final?

risposta

14

Ok, questo è difficile. La tua domanda: "Allora perché Scala non ha semplicemente vietato la combinazione dei modificatori finali privati?" si basa sul presupposto che questa combinazione non ha utilità.

Diciamo che hai ragione (e lo sei, ad eccezione di un piccolo dettaglio, che verrà citato in seguito). Non sono un compilatore, ma dal mio punto di vista "semplicemente proibito" non è probabilmente così semplice (almeno in questo caso). E perché qualcuno dovrebbe tentare di farlo? Quali sono i trade-off? Solo perché qualcosa non è utile non significa necessariamente che faccia del male. Basta non usarlo ...

Ora ecco il piccolo dettaglio che sembra aver trascurato. Il modificatore private è un modificatore di visibilità, il che significa che class B non è a conoscenza dell'esistenza. Ma i modificatori di visibilità di Scala sono un po 'più complessi di quelli di Java. Supponiamo che per qualsiasi ragione tu richieda il codice mostrato nel seguente frammento di codice, il compilatore non lo consentirà.

package scope 

class A { 
    def callFoo = foo; 
    private[scope] final def foo = "bar of A" 
} 
class B extends A { 
    private[scope] final def foo = "bar of B" 
} 

object Main extends App { 
    println((new A()).callFoo) 
    println((new B()).callFoo) 
} 

Questo è uno degli errori forniti dal compilatore: "metodo foo non può prevalere membro finale".

Quindi ecco qui. Scala vieta semplicemente questa combinazione;)

+0

Non ho pensato all'ambito aggiuntivo che può avere un modificatore. Hai ragione, avendo una definizione privata del pacchetto, 'final' proibisce di sovrascriverlo. In questo caso ha un uso. Ma altrimenti penso che un costrutto linguistico senza un effetto non debba essere legale. Qui, se 'final' non impedisce a sottoclassi o tratti di sovrascrivere una definizione di quella che non deve essere usata in una dichiarazione. –

+0

@Tim il motivo 'finale' non impedisce a sottoclassi/tratti che sovrascrivono la definizione è perché' private' lo ha già impedito. I membri 'private' non sono visibili alle sottoclassi quindi non c'è nulla da sovrascrivere. Affinché questo sia un problema, il programmatore dovrebbe fare due errori distinti: 1) provare a sovrascrivere un metodo privato e 2) dimenticare di usare la parola chiave 'override'. È lo stesso in Java, tranne Java è più soggetto a errori poiché l'annotazione '@ Override' è facoltativa. –

3

inizialmente ho pensato che era quello di evitare metodi privati ​​imperativi di classi nidificate, ma a quanto pare non:

class A { 
    private final def foo = 0 

    class B extends A { 
    override def foo = 1 
    } 
} 

error: method foo overrides nothing 
      override def foo = 1 
         ^

Forse è solo per semplificare il refactoring? Quindi, se hai un metodo final, prova a renderlo private, e scopri che non è necessario che sia private dopotutto, non perderai final ity nel processo?

+1

+1 per il punto "prevenzione del refactoring errato"! –

3

Affrontare la questione più ampia,

Allora perché Scala non semplicemente proibiscono la combinazione dei modificatori finali privato?

Questa è una nuova regola e, a questo, una nuova eccezione. Rende la lingua più complessa e assolutamente senza alcun guadagno. Perché rendere le cose più complicate senza una buona ragione?

Questo è il genere di cose che Java fa a cui Odersky non piace molto.Perché la lingua diventi più complessa, ci deve essere qualche guadagno.

+2

La lingua potrebbe diventare più complessa per il parser/compilatore perché deve essere consapevole di tale eccezione. Ma dal punto di vista dell'utente penso che sia più facile quando si è guidati dal compilatore. Un altro esempio potrebbe essere il 'tratto astratto A' contro' tratto A'. Qual è l'uso per affermare esplicitamente che un particolare tratto è 'astratto 'quando questo è vero per tutti i tratti. –

+0

@Tim Non consideri necessario che un utente apprenda _ il _whole_ linguaggio? Dopotutto, non è solo il compilatore che deve supportare la regola - anche il programmatore deve impararlo. –