The following code:
trait A{
val s: String = "A"
println(s"A's initialiser run, s= $s")
}
object O1 extends A {
override val s = "O1"
println(s"Object's initialiser run, s= $s")
def foo: Unit = println("I am just being called to instantiate the object! :| ")
}
object O2 extends AnyRef with A {
override val s = "O2"
println(s"Object's initialiser run, s= $s")
def foo: Unit = println("I am just being called to instantiate the object! :| ")
}
println("////with inheritance:")
O1.foo
println("////with mix-in:")
O2.foo
prints:
////with inheritance:
A's initialiser run, s= null
Object's initialiser run, s= O1
I am just being called to instantiate the object! :|
////with mix-in:
A's initialiser run, s= null
Object's initialiser run, s= O2
I am just being called to instantiate the object! :|
I find the behaviour very strange. I would have expected one of the following behaviours :
"...s = O1","...s = O1""...s = A ","...s = O1"
but neither happens.
I can understand a similar behaviour when s is left an abstract val, as opposed to a def, but I find it weird that the value is simply ignored. My questions are:
- What is happening under the surface that leads to this behaviour ?
- how similar/different does the compiler see the cases of running the initialisation block in a trait with hardcoded value vs a trait with abstract values.
- Why has Scala decided to do this as opposed to the two expected scenarios detailed above.
- Shouldn't the compiler warn us about having anything other than value setting in the body of traits?