Почему невозможно переопределить изменяемую переменную в scala?

Почему невозможно переопределить изменяемую переменную в scala?

class Abs(var name: String){
}

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

Выше кода дает следующую ошибку времени компиляции: -

variable name cannot override a mutable variable

Если имя объявлено val, тогда код выше работает нормально.

Ответ 1

Если вы можете переопределить var с помощью var, то переопределяющий элемент может иметь более узкий тип. (То, как определяется переопределение.)

Затем вы можете назначить значение более широкого типа, а затем прочитать его, ожидая более узкий тип, и выполнить сбой.

Иллюстрация участвующего сеттера:

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

Ответ 2

Короткий ответ: вам нужно передать -Yoverride-vars компилятору Scala.

Согласно спецификации, a var - это как получатель, так и сеттер, и для этих методов применяются нормальные правила переопределения. Однако это показало, что некоторые нежелательные последствия w.r.t. к ключевому слову final и вложению. Код в компиляторе упоминает некоторые уточнения спецификации:

// 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")

Связанный билет: SI-3770

Ответ 3

Я считаю, что целью было просто установить значение унаследованного var name. Это может быть достигнуто таким образом (без override var):

class Abs(var name: String){
}

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

Неоднозначность возникает из локального var name: String в AbsImpl, который назван в честь унаследованного var name: String из Abs. Аналогичный код, менее синтаксически неоднозначный, но также менее элегантный, будет:

class Abs(var name: String){
}

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

Ответ 4

Это происходит, когда var, который вы пытаетесь переопределить, уже имеет назначение. Я не уверен, почему это запрещено, но и это мало смысла.

См. также этот вопрос.

Определите name как абстрактный вместо

trait Abs {
  var name: String
}

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

или

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
  }
}

Ответ 5

Если вы хотите переопределить var, это эквивалентно попытке переопределить поле в java, что невозможно.