The descriptor field is initialized earlier than the fruit field, since the intializes property precedes the class, which extends it. null is the value of the field before initialization - this is why you get it. In the case of def this is just a method call instead of access to a certain field, therefore everything is fine (since the method code can be called several times - there is no initialization). See http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html
Why is def so different? This is because def can be called several times, but val only once (therefore, its first and only call is actually fileld initialization).
A typical solution to this problem is instead, using lazy val , it will be initialized when you really need it. Another solution is the early integrators .
Another, simpler example of what happens:
scala> class A {val a = b; val b = 5} <console>:7: warning: Reference to uninitialized value b class A {val a = b; val b = 5} ^ defined class A scala> (new A).a res2: Int = 0
More generally, scala can theoretically analyze the graph of dependencies between fields (which field needs another field) and begin initialization from the end nodes. But in practice, each module is compiled separately, and the compiler may not even know these dependencies (maybe even Java, which calls Scala, which calls Java), so it simply performs sequential initialization.
Thus, because of this, he could not even detect simple loops:
scala> class A {val a: Int = b; val b: Int = a} <console>:7: warning: Reference to uninitialized value b class A {val a: Int = b; val b: Int = a} ^ defined class A scala> (new A).a res4: Int = 0 scala> class A {lazy val a: Int = b; lazy val b: Int = a} defined class A scala> (new A).a java.lang.StackOverflowError
Actually, such a cycle (inside one module) can theoretically be detected in a separate assembly, but this will not help, since it is quite obvious.