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; thatvaldefinition 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
xdefined inA; now because it is alazy val, it will not be computed before it is needed.You can think of
lazy vals 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.