Scala initialization behaviour

六眼飞鱼酱① 提交于 2019-12-03 12:29:52

问题


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.


回答1:


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


来源:https://stackoverflow.com/questions/3830332/scala-initialization-behaviour

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!