Here There Be Dragons - Dangers of Initialization Order in Scala
One “best practice” in Scala is to use
def for abstract values in a trait, never
val. To wit:
def is preferred is to avoid initialization order weirdness demonstrated below. Basically, the value will first be initialized to its default (
null for references,
0 for integers), and then updated to its correct value.
However, you cannot truly defend against initialization order problems just by using an abstract def instead of a val. This is because an abstract def can be implemented by a val, and this exposes the same problem.
What’s the solution?
You must use either a
def or a
lazy val in the child class, in addition to the abstract
defin the parent trait.
It’s worth pointing out that even though using
lazy val will often fix this problem, it is not foolproof. If a non-lazy val uses the lazy val in its initialization, the same risk exists because you’ve rendered the
lazy modifier useless.
You can actually produce this same error in a plain vanilla class. Terrible, right?
This same sort of error is protected against by the compiler if you try doing that exact same shady business in a function:
That’s all for now.