Why it is not possible to override mutable variable in scala?

北战南征 提交于 2019-11-30 08:33:10

If you could override a var with a var, then the overriding member could have a narrower type. (That's how overriding is defined.)

You could then assign a value of a wider type and then read it expecting the narrower type, and fail.

Illustration of the setter involved:

scala> class A ; class B extends A
defined class A
defined class B

scala> abstract class C { var x: A } ; class D extends C { var x: B = _ }
<console>:13: error: class D needs to be abstract, since variable x in class C of type A is not defined
(Note that an abstract var requires a setter in addition to the getter)
       abstract class C { var x: A } ; class D extends C { var x: B = _ }
                                             ^

scala> abstract class C { var x: A }
defined class C

scala> class D extends C { var x: B = _ ; def x_=(a: A) = ??? }
defined class D

The short answer: you need to pass -Yoverride-vars to the Scala compiler.

According to the spec, a var is both a getter and a setter, and normal overriding rules apply for these methods. However, this proved to have some unwanted consequences w.r.t. to the final keyword and inlining. The code in the compiler mentions some spec clarifications would be needed:

// TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
if (!settings.overrideVars)
  overrideError("cannot override a mutable variable")

A related ticket: SI-3770

I believe that the intent was simply to set the value of the inherited var name. This can be achieved this way (without override var):

class Abs(var name: String){
}

class AbsImpl(name: String) extends Abs(name){
}

The ambiguity arises from the local var name: String in AbsImpl that is named after the inherited var name: String from Abs. A similar code, less syntactically ambiguous but also less elegant would be:

class Abs(var name: String){
}

class AbsImpl(name_value: String) extends Abs(name_value){
}

When you want to overriding a var its equivalent to trying to override a field in java which is not possible.

This happens when the var you are trying to override already has an assignment. I am not sure why this is forbidden, but also it makes little sense.

See also this question.

Define name as abstract instead

trait Abs {
  var name: String
}

class AbsImpl(name0: String) extends Abs {
  var name = name0
}

or

trait Abs {
  var name: String
}

class AbsImpl(private var name0: String) extends Abs {
  def name = {
    println("getter")
    name0
  }

  def name_=(value: String) = {
    println("setter")
    name0 = value
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!