scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.88k stars 1.06k forks source link

abstract `var` can only be overridden when the `override` modifier is not used #21149

Closed symingz closed 4 months ago

symingz commented 4 months ago

Compiler version

3.4.2

Minimized code

File1:

trait C:
  var x: Int

class D extends C:
  var x: Int = 10

File2:

trait C:
  var x: Int

class D extends C:
  override var x: Int = 10

Output

File1 compiles, File2 fails with

-- [E164] Declaration Error: Main.scala:5:15 -----------------------------------
5 |  override var x: Int = 10
  |               ^
  |               error overriding variable x in trait C of type Int;
  |                 variable x of type Int cannot override a mutable variable
1 error found

Expectation

Both File1 and File2 should compile.

Gedochao commented 4 months ago

Hey, so this is actually the intended behaviour, we do not allow to override vars. There used to be a flag for allowing this in Scala 2 (-Yoverride-vars), but not in Scala 3.

What we maybe could consider is adjusting the spec, since we actually don't mention it there, I think. (cc @sjrd) https://www.scala-lang.org/files/archive/spec/3.4/05-classes-and-objects.html#overriding

Either way, closing this.

symingz commented 4 months ago

I see. In this case should File 1 (without the override modifier) be rejected by the compiler as well? Right now the compiler accepts it.

bishabosha commented 4 months ago

overriding is not the same thing as implementing, overriding changes signature, implementing is fine because the types stay the same

symingz commented 4 months ago

I find this confusing. For val and def, one can simply add the override modifier without thinking about if it is implement or override. But then var requires such fine distinction. Furthermore, I have read in multiple places (such as Programming in Scala, 5th Ed) that var is equivalent to two methods (one getter and one setter). From this one would reasonably assume that var can be overridden, but apparently that's not the case. These all seem unnecessary complications. I would rather the language simply ban abstract var, and specify that all var are implicitly final.

bishabosha commented 4 months ago

https://docs.scala-lang.org/sips/sip-tutorial.html

bishabosha commented 4 months ago

you actually can not override a function to have a more precise argument, meaning you can not override a setter, so it makes no sense to override a var, which would override the setter:

scala> trait Foo:
     |   def setFoo(newFoo: Any): Unit
     | trait Bar extends Foo:
     |   override def setFoo(newFoo: String): Unit
     |
-- [E038] Declaration Error: ---------------------------------------------------
4 |  override def setFoo(newFoo: String): Unit
  |               ^
  |   method setFoo has a different signature than the overridden declaration
  |
  | longer explanation available when compiling with `-explain`
1 error found
symingz commented 4 months ago

I don't think that applies to my examples, in

trait C:
  var x: Int

class D extends C:
  override var x: Int = 10

The type for x is always Int.

symingz commented 4 months ago

I am no longer convinced that this is the expected behavior. There are two open issues (#18692, #13019) raising similar questions, and in neither of them was there consensus that this is the expected behavior. If anything, the consensus is that this is an issue that needs to be fixed.

bishabosha commented 4 months ago

ok, comparing to scala 2 behavior it would seem attempt the override as long as the type does not change:

scala> trait Foo {
     |   var x: Any}
trait Foo

scala> class Bar extends Foo {
     |   override var x: Any = 23
     | }
class Bar

scala> class Bar extends Foo {
     |   override var x = 23
     | }
             ^
       error: class Bar needs to be abstract.
       Missing implementation for member of trait Foo:
         def x_=(x$1: Any): Unit = ??? // an abstract var requires a setter in addition to the getter
         override var x = 23
                      ^
On line 2: error: variable x overrides nothing.
       Note: the super classes of class Bar contain the following, non final members named x_$eq:
       def x_=(x$1: Any): Unit
bishabosha commented 4 months ago

saying this is duplicicate of #18692 because the error message is the same