Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rationale for behaviour overriding a val

class A { 
  val x = println("A") 
}
class B extends A {
  override val x = println("B")
}
(new B).x

Prints:

A
B

However,

class A { 
  lazy val x = println("A") 
}
class B extends A {
  override lazy val x = println("B")
}
(new B).x

Prints just:

B

According to Martin Odersky, the behaviour, at least in the non-lazy case, is "as specified". I'm curious as to why the behaviour is specified that way, and why it differs when the val is lazy.

like image 665
Matt R Avatar asked Oct 07 '11 08:10

Matt R


1 Answers

The code in the template ("body") of a class definition, outside of member definitions, is what goes into the constructor. Constructors for parent classes are always called when you initialize an instance of a child class (in this case, you are calling a constructor with no arguments, otherwise the syntax would be class B extends A(arg1, arg2) { ... }). For more details, see Section 5.1 in the Scala Language Specification.

That is why println("A") is evaluated in the first case; that val definition is part of the constructor code.

When you think about what happens at construction time in the second example, you never asked for the value of x defined in A; now because it is a lazy val, it will not be computed before it is needed.

You can think of lazy vals as methods that take no argument and that cache their output the first time they are called. You didn't call that method here, you just defined it.

like image 116
Philippe Avatar answered Sep 21 '22 05:09

Philippe