what happens in scala when loading objects that extends App?

lazy-evaluation, scala

Solution

App extends DelayedInit trait. So all statements and all value definitions are moved to `delayedInit` method. Lazy val works because it compiles to method.

For example if you decompile this class:

class TestApp extends App{
  val test = "I am null"
  lazy val testLazy ="I am a string"
}

You will get class with 'lazy method':

public String testLazy()
{
    if((bitmap$0 & 1) == 0)
        synchronized(this)
        {
            if((bitmap$0 & 1) == 0)
            {
                testLazy = "I am a string";
                bitmap$0 = bitmap$0 | 1;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
    return testLazy;
} 

and delayedInit method in inner class `delayedInit.body`:

 public final class delayedInit.body extends AbstractFunction0
        implements ScalaObject
    {

        public final Object apply()
        {
            $outer.test_$eq("I am null");
            return BoxedUnit.UNIT;
        }

        private final TestApp $outer;
....

So value "I am null" will be assigned to `test` field only when delayedInit is called.

Problem

I've encountered a somewhat bizzar behavior in objects that extends `App`. take a look at the following REPL commands: ``` scala> object A extends App {val x = "I am null"} defined module A scala> object B {val x = "I am a string"} defined module B scala> A.x res0: java.lang.String = null scala> B.x res1: java.lang.String = I am a string ``` well, this is a bit weird... but it gets weirder. i then thought the vals in an `object` go into some lazy evaluation... so i tried a real `lazy val`: ``` scala> object C extends App {lazy val x = "What am I?"} defined module C scala> C.x res2: java.lang.String = What am I? ``` so what's happening here? why is a regular val gets a null value? why does this behavior changes when i use `lazy val`? and what is so special with the `App` trait, that makes the regular vals to be unevaluated?

Original source