Scala inconsistence behavior for final vals with and without type ascription

scala

Solution

Without the type ascription (`: Int`) `number1` doesn't even exist as a field, and therefore doesn't need to be initialized. Instead, the compiler creates an accessor method that returns the value `123` directly, and in the constructor uses the literal value `123` to initialize `str1`.

Why does it create a field when there is a type ascription? It really makes no sense in this case, but sometimes type ascription can require code that does transformations of a value, like boxing a primitive or applying an implicit conversion. These operations should only be done once, both for semantic reasons (object identity, side-effects in the implicit conversion) and for efficiency. Therefore the result must be stored in a field.

So the behavior without a type ascription is an optimization for `final` primitive fields initialized to a constant value, and the compiler isn't smart enough to apply the optimization when a type ascription is present.

Here is a more minimal example:

object TestConstantScala {
  final val brokenStr: String = "foo:" + brokenNumber
  final val brokenNumber: Int = 123
  final val workingStr: String = "foo:" + workingNumber
  final val workingNumber = 123

  println(brokenStr)
  println(workingStr)
}

And here is the output from `scalac -Xprint:constructors`, showing the AST right after moving initialization into the constructor:

[[syntax trees at end of              constructors]] // test18.scala
package <empty> {
  object TestConstantScala extends Object {
    final private[this] val brokenStr: String = _;
    final <stable> <accessor> def brokenStr(): String = TestConstantScala.this.brokenStr;
    final private[this] val brokenNumber: Int = _;
    final <stable> <accessor> def brokenNumber(): Int = TestConstantScala.this.brokenNumber;
    final private[this] val workingStr: String = _;
    final <stable> <accessor> def workingStr(): String = TestConstantScala.this.workingStr;
    final <stable> <accessor> def workingNumber(): Int(123) = 123;
    def <init>(): TestConstantScala.type = {
      TestConstantScala.super.<init>();
      TestConstantScala.this.brokenStr = "foo:".+(scala.Int.box(TestConstantScala.this.brokenNumber()));
      TestConstantScala.this.brokenNumber = 123;
      TestConstantScala.this.workingStr = "foo:".+(scala.Int.box(123));
      scala.this.Predef.println(TestConstantScala.this.brokenStr());
      scala.this.Predef.println(TestConstantScala.this.workingStr());
      ()
    }
  }
}

Notice how there is no field for `workingNumber`, only an accessor, and how in the constructor `workingStr` is initialized with `"foo:".+(scala.Int.box(123))`.

Problem

I am using `scala 2.10.3` and I noticed the following behavior ``` object TestConstantScala { final val str1 : String = "foo:" + number1 final val number1 : Int = 123 final val number2 : Int = 123 final val str2 : String = "foo:" + number2 def main(args: Array[String]){ System.out.println(str1) System.out.println(str2) } } ``` output: ``` foo:0 foo:123 ``` And my question is why the order makes a difference. in addition if I omit the `Int` definition it returns to behave as normal

Original source

Related problems