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?