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