Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what happens in scala when loading objects that extends App?

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?

like image 204
gilad hoch Avatar asked Oct 22 '12 10:10

gilad hoch


1 Answers

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.

like image 163
zvez Avatar answered Oct 24 '22 02:10

zvez