This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Cannot override val with lazy val??

7 replies
Adam Tistler
Joined: 2009-05-18,
User offline. Last seen 42 years 45 weeks ago.

I was a little surprised that scala does not allow you to override a val with a lazy val. I guess that this kind of makes sense since a lazy val is really a function definition that only get evaluated once so
technically it is not immutable?? However you also are not allowed to override a lazy val with a def....hmm

I was also surprised that you cannot override a var with a var. I can't think of a use case where this would cause problems.....hmm.

I decided to test all cases as shown below. Could anyone shed some light on the "why" behind preventing certain override cases.

Base class Overridden by Compiled?
------------------------------------------------------------------------------

lazy val
lazy val yes
val no
var no
def no
val
lazy val no
val yes
var no
def no
var
lazy val no
val no
var no
def no

def
lazy val yes
val yes
var no
def yes
------------------------------------------------------------------------------

Test code:

trait WithLazyVal {
lazy val x = "adam"
}
trait WithVal {
val x = "adam"
}
trait WithDef {
def x = "adam"
}
trait WithVar {
var x = "adam"
}

class Test1 extends WithLazyVal {
override var x = "mike"
}
class Test2 extends WithLazyVal {
override val x = "mike"
}
class Test3 extends WithLazyVal {
override def x = "mike"
}
class Test4 extends WithLazyVal {
override lazy val x = "mike"
}
class Test5 extends WithVal {
override var x = "mike"
}
class Test6 extends WithVal {
override val x = "mike"
}
class Test7 extends WithVal {
override def x = "mike"
}
class Test8 extends WithVal {
override lazy val x = "mike"
}
class Test9 extends WithVar {
override var x = "mike"
}
class Test10 extends WithVar {
override val x = "mike"
}
class Test11 extends WithVar {
override def x = "mike"
}
class Test12 extends WithVar {
override lazy val x = "mike"
}
class Test13 extends WithDef {
override var x = "mike"
}
class Test14 extends WithDef {
override val x = "mike"
}
class Test15 extends WithDef {
override def x = "mike"
}
class Test16 extends WithDef {
override lazy val x = "mike"
}

Results:

scala> trait WithLazyVal {
| lazy val x = "adam"
| }
defined trait WithLazyVal

scala> trait WithVal {
| val x = "adam"
| }
defined trait WithVal

scala> trait WithDef {
| def x = "adam"
| }
defined trait WithDef

scala> trait WithVar {
| var x = "adam"
| }
defined trait WithVar

scala>

scala> class Test1 extends WithLazyVal {
| override var x = "mike"
| }
:7: error: overriding lazy value x in trait WithLazyVal$class of type java.lang.String;
variable x needs to be a stable, immutable value
override var x = "mike"
^

scala> class Test2 extends WithLazyVal {
| override val x = "mike"
| }
:7: error: overriding lazy value x in trait WithLazyVal$class of type java.lang.String;
value x must be declared lazy to override a concrete lazy value
override val x = "mike"
^

scala> class Test3 extends WithLazyVal {
| override def x = "mike"
| }
:7: error: overriding lazy value x in trait WithLazyVal$class of type java.lang.String;
method x needs to be a stable, immutable value
override def x = "mike"
^

scala> class Test4 extends WithLazyVal {
| override lazy val x = "mike"
| }
defined class Test4

scala> class Test5 extends WithVal {
| override var x = "mike"
| }
:7: error: overriding value x in trait WithVal$class of type java.lang.String;
variable x needs to be a stable, immutable value
override var x = "mike"
^

scala> class Test6 extends WithVal {
| override val x = "mike"
| }
defined class Test6

scala> class Test7 extends WithVal {
| override def x = "mike"
| }
:7: error: overriding value x in trait WithVal$class of type java.lang.String;
method x needs to be a stable, immutable value
override def x = "mike"
^

scala> class Test8 extends WithVal {
| override lazy val x = "mike"
| }
:7: error: overriding value x in trait WithVal$class of type java.lang.String;
lazy value x cannot override a concrete non-lazy value
override lazy val x = "mike"
^

scala> class Test9 extends WithVar {
| override var x = "mike"
| }
:7: error: overriding variable x in trait WithVar$class of type java.lang.String;
variable x cannot override a mutable variable
override var x = "mike"
^

scala> class Test10 extends WithVar {
| override val x = "mike"
| }
:7: error: overriding variable x in trait WithVar$class of type java.lang.String;
value x cannot override a mutable variable
override val x = "mike"
^

scala> class Test11 extends WithVar {
| override def x = "mike"
| }
:7: error: overriding variable x in trait WithVar$class of type java.lang.String;
method x cannot override a mutable variable
override def x = "mike"
^

scala> class Test12 extends WithVar {
| override lazy val x = "mike"
| }
:7: error: overriding variable x in trait WithVar$class of type java.lang.String;
lazy value x cannot override a mutable variable
override lazy val x = "mike"
^

scala> class Test13 extends WithDef {
| override var x = "mike"
| }
:7: error: method x_= overrides nothing
override var x = "mike"
^

scala> class Test14 extends WithDef {
| override val x = "mike"
| }
defined class Test14

scala> class Test15 extends WithDef {
| override def x = "mike"
| }
defined class Test15

scala> class Test16 extends WithDef {
| override lazy val x = "mike"
| }
defined class Test16

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Cannot override val with lazy val??

On 4/7/11 2:24 PM, Adam Tistler wrote:
> I was a little surprised that scala does not allow you to override a
> val with a lazy val. I guess that this kind of makes sense since a
> lazy val is really a function definition that only get evaluated once
> so technically it is not immutable?? However you also are not
> allowed to override a lazy val with a def....hmm

Some guideposts:

1) it's never going to let you go from stable to unstable, because it
would throw the type system out the window. That means lazy vals and
vals (stable) cannot be overridden by defs and vars (unstable).

2) Due to open world assumption, separate compilation, and the fact that
superclasses are initialized before subclasses, overriding a val with a
lazy val would probably not work out like you'd want. Maybe it could
technically be allowed but the thought of it fills me with terror, and
that's probably a bad sign.

3) defs can be overridden by vars, so your "Test13" is wrong. But it
(unfortunately) won't let you override only a getter, there has to be a
setter too. This is not for any fundamental reason, it's just messy.

Wanting to override vars with more vars, regardless of the precise list
of issues associated with it, is definitely doing it wrong.

As far as I'm concerned the big missing piece of this puzzle is abstract
lazy val. Previously:

http://www.scala-lang.org/node/2233

E. Labun
Joined: 2010-06-20,
User offline. Last seen 42 years 45 weeks ago.
Re: Cannot override val with lazy val??

There were a lot of questions and confusion regarding initializing and overriding vals, vars, and
lazy vals...

Imaging, we would give up the unified access principle and arrange the things like Groovy did [1]
(see esp. "Property and field rules").

Wouldn't it make the overall logic much more straightforward, flexible, robust, and managable?

[1] Groovy Beans
http://groovy.codehaus.org/Groovy+Beans

--
Eugen

On 2011-04-08 00:44, Paul Phillips wrote:
> Some guideposts:
> ...

Rüdiger Keller
Joined: 2010-01-24,
User offline. Last seen 42 years 45 weeks ago.
Re: Cannot override val with lazy val??

I agree that the whole
constructors/fields/properties/accessors/initialization business is
one of the few "not so nice" points of Scala. I think some improvement
regarding this would be really appreciated by a lot of people, perhaps
for a (backwards incompatible?) 3.0 release.

Regards,
Rüdiger

2011/4/8 Eugen Labun :
> There were a lot of questions and confusion regarding initializing and overriding vals, vars, and
> lazy vals...
>
> Imaging, we would give up the unified access principle and arrange the things like Groovy did [1]
> (see esp. "Property and field rules").
>
> Wouldn't it make the overall logic much more straightforward, flexible, robust, and managable?
>
>
> [1] Groovy Beans
>    http://groovy.codehaus.org/Groovy+Beans
>
> --
> Eugen
>
> On 2011-04-08 00:44, Paul Phillips wrote:
>> Some guideposts:
>> ...
>

Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Cannot override val with lazy val??

I think constructors/fields/accessors and initialization are handled
very consistently in Scala. More so than in other languages with
custom rules and exception to the rules. It may be not as easy to
learn when starting to use the language but it makes much more sense
overall.

On Fri, Apr 8, 2011 at 9:12 AM, Rüdiger Keller
wrote:
> I agree that the whole
> constructors/fields/properties/accessors/initialization business is
> one of the few "not so nice" points of Scala. I think some improvement
> regarding this would be really appreciated by a lot of people, perhaps
> for a (backwards incompatible?) 3.0 release.
>
> Regards,
> Rüdiger
>
>
> 2011/4/8 Eugen Labun :
>> There were a lot of questions and confusion regarding initializing and overriding vals, vars, and
>> lazy vals...
>>
>> Imaging, we would give up the unified access principle and arrange the things like Groovy did [1]
>> (see esp. "Property and field rules").
>>
>> Wouldn't it make the overall logic much more straightforward, flexible, robust, and managable?
>>
>>
>> [1] Groovy Beans
>>    http://groovy.codehaus.org/Groovy+Beans
>>
>> --
>> Eugen
>>
>> On 2011-04-08 00:44, Paul Phillips wrote:
>>> Some guideposts:
>>> ...
>>
>

Rüdiger Keller
Joined: 2010-01-24,
User offline. Last seen 42 years 45 weeks ago.
Re: Cannot override val with lazy val??

I didn't say it wasn't consistent. But judging from feedback on the
lists, etc. there seem to be quite a lot of people who aren't happy
with the current behavior. For example, in general you cannot infer
from a constructor parameter whether it turns into a field without
reading the whole class. That is surely not a desirable property.

Regards,
Rüdiger

2011/4/8 Lex :
> I think constructors/fields/accessors and initialization are handled
> very consistently in Scala. More so than in other languages with
> custom rules and exception to the rules. It may be not as easy to
> learn when starting to use the language but it makes much more sense
> overall.
>
> On Fri, Apr 8, 2011 at 9:12 AM, Rüdiger Keller
> wrote:
>> I agree that the whole
>> constructors/fields/properties/accessors/initialization business is
>> one of the few "not so nice" points of Scala. I think some improvement
>> regarding this would be really appreciated by a lot of people, perhaps
>> for a (backwards incompatible?) 3.0 release.
>>
>> Regards,
>> Rüdiger
>>
>>
>> 2011/4/8 Eugen Labun :
>>> There were a lot of questions and confusion regarding initializing and overriding vals, vars, and
>>> lazy vals...
>>>
>>> Imaging, we would give up the unified access principle and arrange the things like Groovy did [1]
>>> (see esp. "Property and field rules").
>>>
>>> Wouldn't it make the overall logic much more straightforward, flexible, robust, and managable?
>>>
>>>
>>> [1] Groovy Beans
>>>    http://groovy.codehaus.org/Groovy+Beans
>>>
>>> --
>>> Eugen
>>>
>>> On 2011-04-08 00:44, Paul Phillips wrote:
>>>> Some guideposts:
>>>> ...
>>>
>>
>

Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Cannot override val with lazy val??

Definitely. Constructor parameters silently becoming fields is an annoyance.

On Fri, Apr 8, 2011 at 9:40 AM, Rüdiger Keller
wrote:
> I didn't say it wasn't consistent. But judging from feedback on the
> lists, etc. there seem to be quite a lot of people who aren't happy
> with the current behavior. For example, in general you cannot infer
> from a constructor parameter whether it turns into a field without
> reading the whole class. That is surely not a desirable property.
>
> Regards,
> Rüdiger
>

paulbutcher
Joined: 2010-03-08,
User offline. Last seen 10 weeks 5 days ago.
Re: Cannot override val with lazy val??

I've just stumbled across this. The following question is of academic interest only, as I understand it's not going to change, but I'd like to understand :-)

On 7 Apr 2011, at 23:44, Paul Phillips wrote:
> 1) it's never going to let you go from stable to unstable, because it would throw the type system out the window. That means lazy vals and vals (stable) cannot be overridden by defs and vars (unstable).

How is stability encoded in the type system? The only mentions of stability that I can find in the SLS relate to paths and pattern matching (neither of which is what you're talking about above, AFAICT?).

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul [at] paulbutcher [dot] com
AIM: paulrabutcher
Skype: paulrabutcher

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland