class A {
val x = println("A")
}
class B extends A {
override val x = println("B")
}
(new B).x
Prints:
A
B
However,
class A {
lazy val x = println("A")
}
class B extends A {
override lazy val x = println("B")
}
(new B).x
Prints just:
B
According to Martin Odersky, the behaviour, at least in the non-lazy case, is "as specified". I'm curious as to why the behaviour is specified that way, and why it differs when the val is lazy.
The code in the template ("body") of a class definition, outside of member definitions, is what goes into the constructor. Constructors for parent classes are always called when you initialize an instance of a child class (in this case, you are calling a constructor with no arguments, otherwise the syntax would be class B extends A(arg1, arg2) { ... }
). For more details, see Section 5.1 in the Scala Language Specification.
That is why println("A")
is evaluated in the first case; that val
definition is part of the constructor code.
When you think about what happens at construction time in the second example, you never asked for the value of x
defined in A
; now because it is a lazy val
, it will not be computed before it is needed.
You can think of lazy val
s as methods that take no argument and that cache their output the first time they are called. You didn't call that method here, you just defined it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With