Reputation: 43997
I found this explanation on how to propagate overriden member values to superclass constructors by using lazy val. Unfortunately, the article does not explain why this works.
I understand than non-lazy values cannot be assigned twice and that therefore, no value is available in a super constructor since the value assignment in the super class constructor must be skiped in order to not lock the variable to another value. However, how can the println statement - which is executed in the super constructor, i.e. before the new lazy value is asigned - already know about this new value? Am I confusing something about the execution order? Or is println somehow only evaluating its argument after the object is constructed?
Upvotes: 2
Views: 1771
Reputation: 38045
It's pretty simple. You just should note that all fields and lazy fields are getter methods.
val
getter returns value of private[this]
field. private[this]
field assignment is located in primary constructor:
class Test {
val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
def field = _field
{ // constructor
_field = 1
}
}
So before constructor field
returns default value.
lazy val
evaluates block of code using double check lock and than returns result:
class Test {
lazy val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
@volatile private[this] val _flag: Boolean = _
def field = {
if (! _flag) {
synchronized {
if (! _flag) {
_field = 1 // code block
_flag = true
}
}
}
_field
}
}
So lazy val
has nothing with constructor, you'll get same result before and after constructor.
You could check this using scalac -Xprint:mixin test.scala
.
Upvotes: 7