Why we can't override var in scala but can override val

315 views
Skip to first unread message

priyank jain

unread,
Feb 17, 2017, 9:37:29 AM2/17/17
to scala-user
Hi Guys, i am new to Scala and while going through Scala concepts got stumbled over the fact that val can be overridden in Scala but not vars. I am not able to find any convincing answer to this problem. Can someone help me on this

Bardur Arantsson

unread,
Feb 17, 2017, 10:11:15 AM2/17/17
to scala...@googlegroups.com
I believe it's a soundness issue with variance. If you had e.g.

class A() { ... }
class B() extends A() { ... }

trait Foo {
var x: A
}

trait Bar extends Foo {
override var x: B
}

and someone had access to a reference to a Foo, then they might do

foo.x = new A()

which would lead anyone accessing through a Bar reference to try to
access an A as a B... which is obviously not sound.

Regards,

Rex Kerr

unread,
Feb 17, 2017, 6:13:44 PM2/17/17
to Bardur Arantsson, scala-user
This is correct.  The problem is that there isn't anything to override the var *with* that is safe.

Let's suppose we have a superclass `A`, a class `B`, and a subclass `C`.

If you look at the two halves of what a var can do:
  def x: B
  def x_=(b: B): Unit
you can see that the first part works with a subclass; if `C` is a subclass of `B`, then `override def x: C` will certainly be compatible with the superclass `def x: B` because the`C` is a `B`.  And that half is all of what a `val` can do, so it's fine to override a `val`.

If you look at the second half, you need to at least be able to store a `B`.  Storing only a `C` isn't going to cut it, but if you can store an `A` that is a *superclass* of `B`, that is cool too.  So `override def x_=(a: A): Unit` is also fine.  (We don't have a name for this alone.)

If you need to be both, which a var is, well, you can't be a superclass and you can't be a subclass, so you can only be the original class.

And you already are the original class so there's nothing to override at least at the type level.

"But wait!" you say.  "You can override the initial value safely with something else of the same type!"  That's potentially true (assuming you avoid depending on the value in the initializer), and Scala doesn't let you do this directly.

But you can do it, as long as you know you will want to in advance and build in the appropriate machinery:

case class N(value: Int) {}
class Foo { protected def initialN = N(0); var n: N = initialN }
class Bar extends Foo { override protected def initialN = N(1) }

I suppose it wouldn't hurt to allow `override var` to work like this, but right now it doesn't.

  --Rex



--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bardur Arantsson

unread,
Feb 18, 2017, 5:20:21 AM2/18/17
to scala...@googlegroups.com
On 2017-02-18 00:13, Rex Kerr wrote:
> This is correct. The problem is that there isn't anything to override
> the var *with* that is safe.
>
> Let's suppose we have a superclass `A`, a class `B`, and a subclass `C`.
>
[--snip--]

Good point. If invariance were enforced, there'd be no problem. (Still,
it's a pretty niche thing, so it's understandable that it was left out.)

Regards,


Reply all
Reply to author
Forward
0 new messages