Rafael Winterhalter
Rafael Winterhalter

Reputation: 43997

Overriding members and lazy val

I found this explanation on how to propagate overriden member values to superclass constructors by using lazy val. Unfortunately, the article does not explain why this works.

I understand than non-lazy values cannot be assigned twice and that therefore, no value is available in a super constructor since the value assignment in the super class constructor must be skiped in order to not lock the variable to another value. However, how can the println statement - which is executed in the super constructor, i.e. before the new lazy value is asigned - already know about this new value? Am I confusing something about the execution order? Or is println somehow only evaluating its argument after the object is constructed?

Upvotes: 2

Views: 1771

Answers (1)

senia
senia

Reputation: 38045

It's pretty simple. You just should note that all fields and lazy fields are getter methods.

val getter returns value of private[this] field. private[this] field assignment is located in primary constructor:

class Test {
  val field = 1
}

means something like this:

class Test {
  private[this] val _field: Int = _
  def field = _field

  {  // constructor
    _field = 1
  }
}

So before constructor field returns default value.

lazy val evaluates block of code using double check lock and than returns result:

class Test {
  lazy val field = 1
}

means something like this:

class Test {
  private[this] val _field: Int = _
  @volatile private[this] val _flag: Boolean = _

  def field = {
    if (! _flag) {
      synchronized {
        if (! _flag) {
          _field = 1 // code block
          _flag = true
        }
      }
    }

    _field
  }
}

So lazy val has nothing with constructor, you'll get same result before and after constructor.

You could check this using scalac -Xprint:mixin test.scala.

Upvotes: 7

Related Questions