Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is using uninitialized variables allowed in Scala? [duplicate]

Possible Duplicate:
Scala: forward references - why does this code compile?

object Omg {

  class A

  class B(val a: A)

  private val b = new B(a)

  private val a = new A

  def main(args: Array[String]) {
    println(b.a)
  }

}

the following code prints "null". In java. similar construction doesn't compile because of invalid forward reference. The question is - why does it compile well in Scala? Is that by design, described in SLS or simply bug in 2.9.1?

like image 815
jdevelop Avatar asked Aug 29 '12 19:08

jdevelop


People also ask

What happens in Java if you try to use an uninitialized variable?

Local Variables If you cannot initialize your local variable where it is declared, make sure to assign it a value before you attempt to use it. Accessing an uninitialized local variable will result in a compile-time error. Save this answer.

What will happen if you try to access an uninitialized local variable?

There will be no default values or ability to run the code. It will be a compile time error and your code won't run. If the variables were class fields they would get default values for certain types or null otherwise.

What is an uninitialized variable SET TO LET result What is result?

In computing, an uninitialized variable is a variable that is declared but is not set to a definite known value before it is used. It will have some value, but not a predictable one. As such, it is a programming error and a common source of bugs in software.

Is an uninitialized variable a runtime error?

It is not a runtime error.

Why is it mandatory to assign a value to local variable?

Because each local variable has to be initialised, the same memory slot can be reused without ever having to worry about what value is currently in there.


4 Answers

It's not a bug, but a classic error when learning Scala. When the object Omg is initialized, all values are first set to the default value (null in this case) and then the constructor (i.e. the object body) runs.

To make it work, just add the lazy keyword in front of the declaration you are forward referencing (value a in this case):

object Omg {

  class A

  class B(val a: A)

  private val b = new B(a)

  private lazy val a = new A

  def main(args: Array[String]) {
    println(b.a)
  }
}

Value a will then be initialized on demand.

This construction is fast (the values are only initialized once for all application runtime) and thread-safe.

like image 66
paradigmatic Avatar answered Oct 13 '22 00:10

paradigmatic


The way that I understand it, this has to do with how the Scala classes are created. In Java, the class defined above would be initializing the variables inline, and since a had not been defined yet, it could not be compiled. However, in Scala it is more the equivalent of this in Java (which should also produce null in the same scenario):

class Omg {
  private B b = null;
  private A a = null;

  Omg(){ 
    b = new B(a);
    a = new A();
  }
}

Alternately, you could make your declaration of b lazy, which would defer setting the value until it is called (at which time a will have been set).

like image 24
jcern Avatar answered Oct 12 '22 22:10

jcern


As @paradigmatic states, it's not really a bug. It's the initialization order, which follows the declaration order. It this case, a is null when b is declared/init-ed.

Changing the line private val b = new B(a) to private lazy val b = new B(a) will fix issue, since using lazy will delay the init. of b to it's first usage.

It's very likely that this behavior is described in the SLS.

like image 28
pedrofurla Avatar answered Oct 12 '22 23:10

pedrofurla


If this is a concern, compile with -Xcheckinit during development and iterate until the exceptions go away.

Spec 5.1 for template body statements executed in order; beginning of 4.0 for forward references in blocks.

Forward References - why does this code compile?

like image 31
som-snytt Avatar answered Oct 12 '22 22:10

som-snytt