Making the val lazy works because it moves the point where 0.02 is written into the field. To understand what is happening, have a read of the following code, which is the java byte codes that scalac produces for your example.
The thing to notice is that the fields a and b are stored on the child object, and that their values 0.02 and 0.2 are not written until after the constructor of the parent is called. However the println is being invoked in the constructor of the parent, before the fields have been written to. Thus your problem.
Making the vals lazy works because at the point when a() or b() is called, the initialisation code will be called.. that is the parent class will now be calling code on the child class to setup fields on the child class.
public abstract class Function implements scala.ScalaObject {
public abstract double a();
public abstract double b();
public Function(); // NB: calls a() and b() on the child class
Code:
0: aload_0
1: invokespecial #13 // Method java/lang/Object."<init>":()V
4: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: new #21 // class scala/Tuple2$mcDD$sp
10: dup
11: aload_0
12: invokevirtual #25 // Method a:()D
15: aload_0
16: invokevirtual #27 // Method b:()D
19: invokespecial #30 // Method scala/Tuple2$mcDD$sp."<init>":(DD)V
22: invokevirtual #34 // Method scala/Predef$.println:(Ljava/lang/Object;)V
25: return
}
public class ChildFunction extends Function implements scala.ScalaObject {
public double a();
Code:
0: aload_0
1: getfield #12 // Field a:D
4: dreturn
public double b();
Code:
0: aload_0
1: getfield #14 // Field b:D
4: dreturn
public ChildFunction(); // NB invokes parent constructor BEFORE writing values to fields a and b.
Code:
0: aload_0
1: invokespecial #20 // Method Function."<init>":()V
4: aload_0
5: ldc2_w #21 // double 0.02d
8: putfield #12 // Field a:D
11: aload_0
12: ldc2_w #23 // double 0.2d
15: putfield #14 // Field b:D
18: return
}
You can 'fix' this issue by using defs instead of lazy val (example below). Or better yet, remove the println and only invoke a() and b() after ChildFunction has been fully constructed.
object StackOverflowTest extends App
{
new ChildFunction()
}
abstract class Function() {
def a: Double
def b: Double
println(a, b)
}
class ChildFunction() extends Function() {
override def a = 0.02
override def b = 0.2
}