Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala initialization behaviour

Please look at the following code.

trait MyTrait { val myVal : String }

class MyClass extends MyTrait { val myVal = "Value" }

class MyClass2(val myVal: String) extends MyTrait 

Why does the initialization order differ in case of MyClass and MyClass2? The constructor of MyClass will be as

MyClass() {
  MyTrait$class.$init$(this);
  myVal = value
}

The constructor of MyClass2 will be

MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) }

I think the initialization order should be as MyClass2's constructor does, the same for both cases.

like image 562
Dmitry Avatar asked Sep 30 '10 12:09

Dmitry


People also ask

What does lazy val do?

A lazy val is most easily understood as a "memoized (no-arg) def". Like a def, a lazy val is not evaluated until it is invoked. But the result is saved so that subsequent invocations return the saved value. The memoized result takes up space in your data structure, like a val.

What is INIT in Scala?

In Scala Stack class , the init() method is utilized to return a new stack that consists of all the elements except the last one. Method Definition: def init: Stack[A] Return Type: It returns a new stack that consists of all the elements except the last one.

Can Scala object have constructor?

Constructors in Scala describe special methods used to initialize objects. When an object of that class needs to be created, it calls the constructor of the class. It can be used to set initial or default values for object attributes.

What is constructor parameter in Scala?

Scala constructor is used for creating an instance of a class. There are two types of constructor in Scala – Primary and Auxiliary. Not a special method, a constructor is different in Scala than in Java constructors. The class' body is the primary constructor and the parameter list follows the class name.


1 Answers

At the end of section 5.1 of the Scala specification, the following is defined:

Template Evaluation. Consider a template sc with mt 1 with mt n {stats}. If this is the template of a trait (§5.3.3) then its mixin-evaluation consists of an eval- uation of the statement sequence stats. If this is not a template of a trait, then its evaluation consists of the following steps.

  • First, the superclass constructor sc is evaluated (§5.1.1).
  • Then, all base classes in the template’s linearization (§5.1.2) up to the template’s superclass denoted by sc are mixin-evaluated. Mixin-evaluation hap- pens in reverse order of occurrence in the linearization.
  • Finally the statement sequence stats is evaluated.

Note, however, that the constructor parameters may be used by any constructors that follow it. Therefore, it needs to be initialized before them. This is made explicit at the end of section 5.1.1:

An evaluation of a constructor invocation x.c targs. . .(argsn) consists of the following steps:

  • First, the prefix x is evaluated.
  • Then, the arguments args1 , . . . , argsn are evaluated from left to right.
  • Finally, the class being constructed is initialized by evaluating the template of the class referred to by c.

This you don't have any problem with, but you do have a problem with {stats} being executed last. The reason why {stats} is executed last is that it may reference attributes of its ancestor classes and traits, whereas the ancestors obviously have no knowledge about its descendants. Therefore, the ancestors need to be fully initialized before {stats} gets executed.

Of course, it is possible that you do need early initialization. This is covered by section 5.1.6: Early Definitions. Here's how you'd write it:

class MyClass extends { val myVal = "Value" } with MyTrait
like image 144
Daniel C. Sobral Avatar answered Sep 28 '22 02:09

Daniel C. Sobral