Scala lazy value interpretation

I am learning Scala basics. I just came across the concept lazy val

. I have the following code snippets working without errors / warnings

Case 1

lazy val a = 10 + b
lazy val b = 5
println(a)

      

Case 2

lazy val a = 10 + b
val b = 5
println(a)

      

Case 3

val a = 10 + b
lazy val b = 5
println(a)

      

I understand how it works case 1 & 2

. But I don't understand how the code case 3

without error / warning works . How can Scala evaluate a value a

when b

not yet defined?

EDIT

I am not running this code in Scala REPL

. I saved the code for case 3 in a file called lazyVal.scala

. I am doing it with scala lazyVal.scala

. I think Scala interprets the code in the file.

If I change the code in lazyVal.scala

to

val a = 10 + b
val b = 5
println(a)

      

And run it using scala lazyVal.scala

I get a warning

/Users/varun.risbud/scalaRepo/src/Chapter1/lazyVal.scala:1: warning: Reference to uninitialized value b
val a = 10 + b
         ^
one warning found
10

      

Also if I change the code to create the object and extend the application it works

object lazyVal extends App {
    val a = 10 + b
    lazy val b = 5
    println(a)
}
  Chapter1 scalac lazyVal.scala
  Chapter1 scala lazyVal
15

      

My scala version

- 2.12.1

if it matters.

+3


source to share


1 answer


The statements in the constructor are executed in text order, so you get a warning when initialization a

refers to uninitialized b

. It's a common mistake to create a class in such a way that you don't even get a warning. (There is a tutorial on the subject.)

The same text is prohibited in the local sequence of statements:

scala> :pa
// Entering paste mode (ctrl-D to finish)

locally {
val a = 10 + b
lazy val b = 5
println(a)
}

// Exiting paste mode, now interpreting.

<console>:13: error: forward reference extends over definition of value a
       val a = 10 + b
                    ^

      

As members of a class or object, the lazy member is evaluated "on demand" when a

evaluated at build time.

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X {
val a = 10 + b
lazy val b = 5
println(a)
}

// Exiting paste mode, now interpreting.

defined object X

scala> X
15
res1: X.type = X$@6a9344f5

      



The script runner wraps your lines of code like this:

object X {
  def main(args: Array[String]): Unit =
    new AnyRef {
      val a = 10 + b
      lazy val b = 5
      println(a)
    }
}

      

If you give it an object with main

or that extends App

, it won't wrap the code, but just use it directly.

There are subtle differences between the three formulations. For example, the constructor of a top-level object runs as a static initializer; but App

has special code to run init code like main

. (They get rid of App

because it's confusing.)

+5


source







All Articles