I have been bitten a number of times by a situation like this:
trait MyTrait {
val implementMe: String
val upper = implementMe.toUpperCase
}
class MyClass(s: String) extends MyTrait {
override val implementMe: String = s
}
val c = new MyClass("Hello, World")
println(c.upper)
In this example, everything compiles but the last line throws a NullPointerException at runtime, (I assume) because upper
is computed before implementMe
is actually defined.
I know I can fix it by changing upper
to a def
or a lazy val
but it seems like this should be caught at compile time rather than runtime. Am I doing something wrong/is there a way this sort of problem can be detected at compile time? Is there a reason the compiler allows this?