Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala fails to initialize a val

I have found kind of a weirdness in the following Scala program (sorry to include all the code, but you'll see why I added it all) :

object md2html extends App {
    private val DEFAULT_THEME = Themes.AMAZON_LIGHT

    private val VALID_OPTIONS = Set("editorTheme", "logo", "style")
    try {
        // some code 1
    } catch {
        case t: Throwable => t.printStackTrace(); exitWithError(t.getMessage)
    }

    // some code 2 (method definitions only)

    private def parseOption(key: String, value: String) = {
        println(key + " " + VALID_OPTIONS)
        if (! Set("theme","editorTheme", "logo", "style").contains(key)) exitWithError(s"$key is not a valid option")   
        if (key == "theme") Themes(value).toMap else Map(key.drop(2) -> value)
    }

    // some code 3 (method definitions only)
}

If VALID_OPTIONS is defined after one of the some code..., it is evaluated to null in parseOption. I can see no good reason for that. I truncated the code for clarity, but if some more code is required I'll be happy to add it.

EDIT : I looked a bit more into it, and here is what I found.

When extending App, the val is not initialized with this code

object Test extends App {
    printTest()
    def printTest = println(test)
    val test = "test"
}

With a regular main method, it works fine :

object Test {
    def main(args: Array[String]): Unit = {
      printTest
    }
    def printTest = println(test)
    val test = "test"
}
like image 369
Dici Avatar asked May 24 '15 18:05

Dici


People also ask

What does lazy val mean in Scala?

Scala provides a nice language feature called lazy val that defers the initialization of a variable. The lazy initialization pattern is common in Java programs. Though it seems tempting, the concrete implementation of lazy val has some subtle issues.

How is lazy val implemented in Scala?

The current lazy val initialization scheme uses double-checked locking to initialize the lazy val only once. A separate volatile bitmap field is used to store the state of the lazy val - a single bit in this bitmap denotes whether the lazy val is initialized or not.

How do you change the value of Val in Scala?

val is immutable. If you wanna change the value, you should use var instead.


Video Answer


1 Answers

I had overseen that you use extends App. This is another pitfall in Scala, unfortunately:

object Foo extends App {
  val bar = "bar"
}

Foo.bar            // null!
Foo.main(Array())
Foo.bar            // now initialized

The App trait defers the object's initialization to the invocation of the main method, so all the vals are null until the main method has been called.

In summary, the App trait and vals do not mix well. I have fallen into that trap many times. If you use App, avoid vals, if you have to use global state, use lazy vals instead.

like image 157
0__ Avatar answered Nov 05 '22 07:11

0__