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.
source to share
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.)
source to share