Only when we get to the constructor of C are both x1 and x2 initialized. Therefore, constructors of A and B risk running into NullPointerExceptions.

Explanation

A ‘strict’ or ‘eager’ val is one which is not marked lazy.

In the absence of “early definitions” (see below), initialization of strict vals is done in the following order.

Superclasses are fully initialized before subclasses.

Otherwise, in declaration order.

Naturally when a val is overridden, it is not initialized more than once. So though x2 in the above example is seemingly defined at every point, this is not the case: an overridden val will appear to be null during the construction of superclasses, as will an abstract val.

There is a compiler flag which can be useful for identifying this situation:

-Xcheckinit: Add runtime check to field accessors.

It is inadvisable to use this flag outside of testing. It adds significantly to the code size by putting a wrapper around all potentially uninitialized field accesses: the wrapper will throw an exception rather than allow a null (or 0/false in the case of primitive types) to silently appear. Note also that this adds a runtime check: it can only tell you anything about code paths which you exercise with it in place.

Early definitions are a bit unwieldy, there are limitations as to what can appear and what can be referenced in an early definitions block, and they don’t compose as well as lazy vals: but if a lazy val is undesirable, they present another option. They are specified in SLS 5.1.6.