For question about difference between new { type T = Int ; val init = 10 }
with AbsCell2 and new AbsCell2 { type T = Int ; val init = 10 }
。
The first one is the so-called early-initializers or pre-initialized fields(mentioned in Abstract Members chapter in Programming In Scala)。It allows the subclass to initialize fields before the super class is called。
In this case, init has already been set as 10 before the initialization of AbsCell2。
The latter one is normal inheritance, it creates an anonymous class then extends AbsCell2, just like:
class AbsCell' extends AbsCell {
type T = Int
val init = 10
}
However, the anonymous class gets initialized after the abstract class AbsCell2, so init are not available in the initialization of itself, namely, init is the default value of the Type, 0 in this case. Therefore, you get 0 in the print。
use scalac -Xprint:all Test.scala
, you will see the following:
abstract class AbsCell2 extends Object {
<stable> <accessor> def init(): Object;
....
def <init>(): AbsCell2 = {
AbsCell2.super.<init>();
AbsCell2.this.value = {
scala.this.Predef.println("Hello ".+(AbsCell2.this.init()));
AbsCell2.this.init()
};
()
}
};
// normal initialization
final class anon$1 extends AbsCell2 {
private[this] val init: Int = _;
<stable> <accessor> def init(): Int = anon$1.this.init;
....
def <init>(): <$anon: AbsCell2> = {
anon$1.super.<init>();
anon$1.this.init = 10;
()
}
};
// early initialization
final class anon$2 extends AbsCell2 {
private[this] val init: Int = _;
<stable> <accessor> def init(): Int = anon$2.this.init;
....
def <init>(): <$anon: AbsCell2> = {
val init: Int = 10;
anon$2.this.init = init;
anon$2.super.<init>();
()
}
}
From the code, we can see that for normal initialization, init is set to 3 after the initialization of super class AbsCell2, when AbsCell2.this.init() gets invoked, it actually refers to the subclass' init field and 3 is yet to set, so we get the default type value。On the contrary, early initialization first set init to 3 then call super class initialization。