Unexpected initialization result when val depends on null var

scala version: 2.12.12

class TestFieldInit() {
  private val x = {
    _a = "12345"
    _a
  }

  private var _a: String = null

  private val y = _a

  // _a: String = null -> x=12345, y=null, _a=null
  // _a: String = _ -> x=12345, y=12345, _a=12345
  println(s"x=$x, y=$y, _a=${_a}")
}

Hi, as you can see, when I initialize _a with null, I’d get both y and _a as null. However, if I initialize the _a with _, I’d get my expected value. Is it a bug? Otherwise, could anyone help me understand what happens here? Thanks in advance.

Hi.

Please enclose code in triple backticks when posting ```` – that makes it much easier to read and copy your code.

Fields of a class are just initialized in the order given:

  1. x is initialized (which sets the uninitialized variable _a to "12345" as a side effect)
  2. _a is initialized (only in case you assign a value to it – not when using = _)
  3. y is initialized

So, basically you overwrite the already assigned value in step 2, when you use = null.

Note that with Scala 2.13 you get two warnings for your code:

Main.scala:3: warning: Reference to uninitialized variable _a
    _a = "12345"
    ^
Main.scala:4: warning: Reference to uninitialized variable _a
    _a
    ^

because you’re setting / accessing a uninitialized variable.

3 Likes

thank you @cbley

A workaround is the idiom var x: X = x, which assigns to x its current value.

When they debated how to get rid of var x: X = _ syntax, I proposed this, possibly inspired by Laurie Anderson, Let X = X.

Scala 3 instead has uninitialized and more checks for initialization, nullability, etc.

➜  ~ scala
Welcome to Scala 2.13.7 (OpenJDK 64-Bit Server VM, Java 17).
Type in expressions for evaluation. Or try :help.

scala> class C {
     | private val x = { _a = "123" ; _a }
     | private var _a: String = _a
     | private val y = _a
     | def f = (x, _a, y)
     | }
       private var _a: String = _a
                                ^
On line 3: warning: variable _a in class C does nothing other than call itself recursively
       private val x = { _a = "123" ; _a }
                         ^
On line 2: warning: Reference to uninitialized variable _a
       private val x = { _a = "123" ; _a }
                                      ^
On line 2: warning: Reference to uninitialized variable _a
class C

scala> new C().f
val res0: (String, String, String) = (123,123,123)