Why is it not possible to override `var` with` def` in Scala?

Although I understand why var cannot override val in a subclass and vice versa, I cannot understand why Scala does not allow def in a subclass to override var in a superclass

 class Car { var age = 32 } class SedanCar extends Car { override def age = 54 } 

Since var is mutable, why not let a def override it? Can someone help me in understanding this?

+5
source share
2 answers

What is connected with the Liskov replacement principle : you cannot assign weaker access rights to a subclass (even for Java) . Creating var a def makes setter def x_= (y: T ): Unit private (as pointed out by @Staix). Therefore, if Seadan Car has a formal Car type, it should not be accessed, but the compiler cannot find such cases at all (only formal types are known at compile time), therefore this behavior is disabled, like any weaker privilege:

  val car2 = new SeadanCar car.age = 422 //compiler error, can't mutate "def age" val car: Car = new SeadanCar car.age = 42 //now you had mutated immutable 

The point of the principle of substitutability is behavior that cannot be changed after casting in a supertype.

On the other hand, scala can only redefine part of the getter variable, as @ Régis Jean-Gilles said, but this is not such an obvious solution because intuitively the user expects var become unchanged after override def . And this actually violates the Uniform Access Principle , because you should see that your var as two services (reader and writer), and not one, is true, while UAP compatibility requires the opposite: both the reader and the writer should be represented by one unified notation.

PS Actually, your question indicates incomplete compatibility with scala UAP compatibility. As I said, overriding only reading var and leaving a record like this will not be compatible with UAP is blocking the ability to redefine var (so you cannot redefine var in both directions: computational and memory), even regardless of the fact that you are no longer can override it due to LSP. But the current scala solution is also problematic. You may find that you can:

  trait Car { def age: Int = 7; def age_=(a: Int) = {}} class SeadanCar extends Car { override def age: Int = 5} 

But can't

  // just repeating your example trait Car { var age: Int = 7 } class SeadanCar extends Car { override def age: Int = 5} 

So scala inheritance seems incompatible with UAP. IMHO, the big problem is that the reader and var itself have the same names, so you cannot distinguish them (when defining, not when accessing). I would resolve this with something like:

  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} 

Note that overriding age_ in my suggested example should result in:

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

I do not like:

  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 

Of course, this approach should turn off the var age and def age_; def age_= def age_; def age_= at the same time:

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

but it is difficult to implement in scala due to backward compatibility

PS / 2 Just to mention, regarding the issue of mutability / immutability of the question, you definitely cannot do this (due to LSP):

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

And due to LSP + UAP, this should not be:

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

no matter what you can :)

+12
source

I think you have a problem with the concept. From the Scala links:

The declaration of the var x: T variable is equivalent to the declarations of the getter function x and the setter function x_ =, defined as follows:

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

So, you are trying to override the getter "age = 54". But now you have no use for the setter.

I hope you understand what I mean. I think why people “minus” your question, because you don’t think in Scala thinking here.

0
source

Source: https://habr.com/ru/post/980402/


All Articles