In Scala 2.10.4, Given the following class:
scala> class Foo {
| val x = true
| val f = if (x) 100 else 200
| }
defined class Foo
The following two examples make sense to me:
scala> new Foo {}.f
res0: Int = 100
scala> new Foo { override val x = false}.f
res1: Int = 200
But, why doesn't this call return 100
?
scala> new Foo { override val x = true }.f
res2: Int = 200
Because vals aren't initialized more than once, x
is actually null
(or false
for a default Boolean
) during the initialization of Foo
, and then initialized in the anonymous class that is extending Foo
in your example.
We can test it more easily with an AnyRef
:
class Foo {
val x = ""
val f = if (x == null) "x is null" else "not null"
}
scala> new Foo { override val x = "a" }.f
res10: String = x is null
scala> new Foo {}.f
res11: String = not null
There's a full explanation in the Scala FAQ. Excerpt:
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.
A simple way to avoid this would be to use a lazy val or def, if the val being referenced may be overridden.
Additionally, you can use the -Xcheckinit
compiler flag to warn you about potential initialization errors like this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With