2014-12-23 4 views
5

Während ich verstehe, warum ein var keine val in der Unterklasse und vice versa außer Kraft setzen kann, bin ich nicht in der Lage zu verstehen, warum Scala keine def in der Unterklasse erlaubt ein var in SuperWarum ist es unmöglich in Scala `var` mit` def` zu überschreiben?

class Car { 
    var age = 32 
} 

class SedanCar extends Car { 
    override def age = 54 
} 

Als var außer Kraft zu setzen ist wandelbar, warum nicht zulassen, dass ein def es überschreiben? Kann mir bitte jemand helfen, dies zu verstehen?

+1

Weil Defs sind nicht veränderbar, sondern Methodendefinitionen. Was willst du machen, wenn du in SedanCar "Alter = 32" machst? –

+5

Ich denke OP's Frage ist völlig in Ordnung. Scala wird oft aus gutem Grund als dem einheitlichen Zugangsprinzip folgend angesehen. Es wäre daher nicht unvernünftig zu sehen, dass die 'age'-var-Definition nichts anderes ist als die Definition eines Paares von Getter- und Setter-Methoden (' age' und 'age_ ='). In diesem Fall sollte ich definitiv 'age' überschreiben können, was nur den Getter überschreiben und den Setzer unverändert lassen würde. –

Antwort

12

Das ist mit dem Liskov Substitution Principle verwandt: Sie können weaker access privileges in subclass (even for Java) nicht zuordnen. Making var ein def macht den Setter def x_= (y: T): Unit privat (wie @Staix sagte). Also in dem Fall, wenn Seadan Car hat formalen Typ Car - es sollte nicht zugegriffen werden, aber der Compiler kann solche Fälle im Allgemeinen nicht finden (nur formale Typen sind in der Kompilierzeit bekannt), so dass Verhalten wie jedes schwächere Privileg deaktiviert ist:

Der Punkt der Substituierbarkeit Prinzip ist das Verhalten sollte nicht nach dem Gießen auf den Supertyp geändert werden.

Auf der anderen Seite, scala nur Getter Teil der Variablen außer Kraft setzen könnte als @ Régis Jean-Gilles sagte, dies ist aber nicht so nahe liegende Lösung, weil intuitiv erwarten Benutzer ein var nach override def unveränderlich werden. Und es verletzt tatsächlich Uniform Access Principle, weil Sie Ihre var als zwei Dienste (Leser und Schreiber) sehen müssen, statt einer ist es wirklich, während UAP-Kompatibilität das Gegenteil erfordert: beide Leser und Schreiber sollten durch eine einheitliche Notation dargestellt werden.

P.S. Eigentlich weist deine Frage auf die Unvollständigkeit der UAP-Kompatibilität von scala hin. Wie gesagt, das Überschreiben von var 's Leser und das Verlassen von Writer wird mit UAP inkonsistent sein - es blockiert die Fähigkeit, var selbst zu überschreiben (so kann man var nicht auf zwei Arten überschreiben: Rechen- und Speicher-ähnlich), auch wenn Sie können sie aufgrund von LSP nicht überschreiben. Aber auch die aktuelle Lösung von scala ist problematisch. Sie können feststellen, dass Sie:

trait Car { def age: Int = 7; def age_=(a: Int) = {}} 

class SeadanCar extends Car { override def age: Int = 5} 

aber nicht

// just repeating your example 

trait Car { var age: Int = 7 } 

class SeadanCar extends Car { override def age: Int = 5} 

So Scalas Erbe scheint nicht mit UAP kompatibel zu sein. IMHO, das große Problem ist, dass Leser und Var selbst identische Namen haben - so können Sie sie nicht unterscheiden (beim Definieren, nicht beim Zugriff).Ich würde löst es mit so etwas wie:

trait Car { def age_: Int = 7; def age_=(a: Int) = {}} 
class SeadanCarReadOnly extends Car { override def age: Int = 5} //can't compile as reader is closed 
class SeadanCarVar extends Car { override var age: Int = 5} 
class SeadanCarReadOnly extends Car { override def age_: Int = 5} 

trait Car2 { var age = 100500 } 
class SeadanCarReadOnly extends Car2 { override def age_: Int = 5} 

Hinweis, dass age_ in meinem vorgeschlagenen Beispiel zwingende sollte führen zu:

scalaxx> (new SeadanCarReadOnly).age //call age_ here 
resxx: Int = 5 

scalaxx> (new SeadanCarReadOnly).age_ 
resxx: Int = 5 

Nicht wie:

trait Car2 { @BeanProperty var age = 100500 } 
class SeadanCarReadOnly extends Car2 { override def getAge: Int = 5} 

//which leads to inconsistency: 

scala> (new SedanCar()).age 
res6: Int = 30 

scala> (new SedanCar()).getAge 
res7: Int = 54 

Von cource, wie Ansatz sollte Deaktivieren var age und def age_; def age_= gleichzeitig deaktivieren:

trait Car2 { var age = 100500 } 
class SeadanCarReadOnly extends Car2 { 
    override var age = 17; 
    override def age_: Int = 5 //should be compile error here 
} 

aber das ist schwer zu schnell es in Scala Sprache zu implementieren aufgrund der Abwärtskompatibilität

PS/2 Nur zu erwähnen, in Bezug auf Veränderlichkeit/immutabilty Teil der Frage, auf jeden Fall können Sie dies nicht tun (aufgrund LSP):

trait Car { var age: Int = 32 } //or without initial value 
class SedanCar extends Car { override val age = 42 } 

Und aufgrund LSP + UAP sollte nicht in der Lage sein, dies zu tun:

trait Car { def age: Int = 7; def age_=(a: Int) = {}} 
class SedanCar extends Car { override val age = 42 } 

regardl Ess die Tatsache, dass Sie :)

+1

Ich kann den "was Benutzer erwarten" -Teil kaufen, aber ich stimme respektvoll zu, dass das Überschreiben nur des Getters das UAP verletzen würde. Immerhin kann man dabei noch "Alter" lesen oder schreiben, indem man auf "Alter" verweist. Ich sehe nicht, wie es mehr von einer "einheitlichen Notation" sein könnte. Ich kann mir Gründe für diese Einschränkung vorstellen, aber das Brechen der UAP gehört nicht dazu, ganz im Gegenteil. –

+0

Als Nebenbemerkung ist mir eigentlich egal, dass man den Getter nicht alleine übersteuern kann. Aber in der Tat können Sie eine Var überhaupt nicht überschreiben und das ist ein Mist. –

+0

1) 'var' ist eine einheitliche Notation,' get' + 'set' ist nicht. wenn du sagst: "Lass uns nur überstürzen!" - Sie bevorzugen offensichtlich die zweite und drängen den Benutzer, über Getter/Setter nachzudenken. 2) Ich denke, dass mein Beispiel mit formalen Typ darstellbar genug ist, um zu sehen, warum Sie var "überhaupt" nicht überschreiben können. – dk14

0

Ich denke, Sie haben ein Problem mit dem Konzept. Von Scala Referenzen:

Eine Variablendeklaration var x: T entspricht Erklärungen eines Getter Funktion x und eine Set-Funktion x_ =, de fi niert wie folgt:

def x: T 
def x_= (y: T): Unit 

Also Sie versuchen, außer Kraft setzen ein Getter von "Alter = 54". Aber jetzt hast du keinen Nutzen mehr für den Setter.

Ich hoffe, Sie bekommen, was ich meine. Ich denke, warum Leute "minus" deine Frage sind, weil du hier nicht in der Denkweise von Scala denkst.

+4

Ihre Antwort zeigt genau auf den Kern des Problems: 'var x: T 'soll äquivalent zu' def x: T sein; def x_ = (y: T): Einheit', ist es aber nicht. Mit der letztgenannten Definition bin ich völlig berechtigt, den Getter nur zu überschreiben und den Setzer so zu lassen, wie er ist. Das stimmt nicht mit der Var-Definition. –

+3

Hahahahaha, noch ein Scala Spezifikationsfehler. Ordentlich! – gzm0

+0

@ RégisJean-Gilles Eine Deklaration ist keine Definition. –

Verwandte Themen