Steve B.
Steve B.

Reputation: 57274

scala: instance variables and object initialization

I've been thinking of scala objects as simply shorthand for singleton java objects - that is, I'd expect them to behave like objects with guaranteed singleton instantiation. Then I run into something like this, which I don't understand:

object Test  extends App{
 var x ="a"

 override def main(args:Array[String]):Unit = {
   println(x )
 }
}

which prints null rather than "a".

Looking at the generated classes, I get a Test$.class which is the object definition; however the instance value "a" is defined in a companion Test class using a generated delayedInit. Can someone shed some light on how this is instantiated? Clearly the mental model I had of this is incorrect.

Upvotes: 3

Views: 1912

Answers (1)

Akos Krivachy
Akos Krivachy

Reputation: 4966

Let's first take a look at App and how it works. The documentation of App reveals the following caveats:

It should be noted that this trait is implemented using the DelayedInit functionality, which means that fields of the object will not have been initialized before the main method has been executed.

It should also be noted that the main method will not normally need to be overridden: the purpose is to turn the whole class body into the “main method”. You should only chose to override it if you know what you are doing.

Your example

Ok, great. Now that we know these two facts, let's fix your code. There are two possible solutions we can consider:

Let's only override the main method when we know what we're doing:

object Test extends App{
 var x ="a"
 println(x )
}

Or we can choose to define a main method, but not extend App:

object Test {
 var x ="a"

 def main(args:Array[String]):Unit = {
   println(x )
 }
}

Conclusion

You're understanding of objects is correct. What's confusing is the DelayedInit that App implements. Happy coding ;)

Upvotes: 4

Related Questions