Forward References – why does this code compile?

The body of a class or an object is the primary constructor. A constructor, like a method, is a sequence of statements that are executed in order — to do anything else, it would have to be a very different language. I’m pretty sure you wouldn’t like for Scala to execute the statements of your methods in any other order than sequential.

The problem here is that the body of classes and objects are also the declaration of members, and this is the source of your confusion. You see val declarations as being precisely that: a declarative form of programming, like a Prolog program or an XML configuration file. But they are really two things:

// This is the declarative part
object A {
  val b
  val c
}

// This is the constructor part
object A {
  b = c
  c = "foo"
}

Another part of your problem is that your example is very simple. It is a special case in which a certain behavior seems to make sense. But consider something like:

abstract class A {
  def c: String
}

class B extends A {
  val b = c
  override val c = "foo"
}

class C extends { override val c = "foobar" } with B

val x = new C
println(x.b)
println(x.c)

What do you expect to happen? The semantics of constructor execution guarantees two things:

  1. Predictability. You might find it non-intuitive at first, but the rules are clear and relatively easy to follow.
  2. Subclasses can depend on superclasses having initialized themselves (and, therefore, its methods being available).

Output:

it will print “foobar” twice for more => https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html

Leave a Comment