Description
Compiler version
3.7.0 Next and 3.3.6 LTS
Minimized code
Implementing an abstract var with a val is unsound but compiles. It is unsound because a non-abstract class should be required by the type-checker to implement all abstract methods. The mutable variable requires a setter definition, but implementing it with a constant val does not define a setter.
scastie for code below: https://scastie.scala-lang.org/qh1Vo7vZSmSCBJ84kcyoTw
trait Comment {
var comment: String
}
final case class Y(val comment: String) extends Comment {}
object Main {
def main(args: Array[String]): Unit = {
val y = Y("foo")
println(y)
println(y.comment)
println("-----")
y.comment = "Bar" // AbstractMethodError
println(y)
println(y.comment)
println("-----")
}
}
this alternate definition of Y will also compile and throw the same error at runtime:
final class Y extends Comment {
def comment: String = "a"
}
Output
java.lang.AbstractMethodError: Method Y.comment_$eq(Ljava/lang/String;)V is abstract
at Y.comment_$eq(main.scala)
at Main$.main(main.scala:15)
at Main.main(main.scala)
Expectation
Implementing an abstract var
with a val
is not a sound thing to do, so this should lead to a compile-time error.
c.f. this code which correctly returns a compile-time error. i would expect the first code example to have a similar error.
trait Comment {
def comment: String
def comment_=(x: String): Unit
}
final case class Y(val comment: String) extends Comment {}
class Y needs to be abstract, since def comment_=(x: String): Unit in trait Comment is not defined
This also reveals a difference in behaviour between a var
and separately-defined getter and setter methods, in contravention of 4.2 Variable Definitions.
Related issues
It is important to note that this issue is about implementing an abstract var, not overriding, so it should not be confused with the many bug reports about overriding.
Regarding var/val/def implementations of abstract members, there could be a number of cases to explore here. Namely, var vs val vs def getter vs def getter+setter and each of these 4 cases can be in the trait or the implementation, leading to 16 cases in total.