Question regarding lazy evaluation

``````Here is an example of two functions presented in the Book,
Functional Programming In Scala. I am curious about the output of the second
example, maybeTwice2. Why are there not two "hi" s printed?  I am ware that
the purpose of the example is to illustrate lazy evaluation. But still wonder why "hi"
is not printed twice. Can some scala guru please explain?

def maybeTwice(b: Boolean, i: => Int) =
if ( b ) {
i + i
} else 0

scala> val x = maybeTwice(true, { println("hi"); 1+41 })
hi
hi
x: Int = 84

scala> def maybeTwice2(b: Boolean, i: => Int) = {
lazy val j = i
if ( b ) j + j else 0
}
scala> val x = maybeTwice2(true, { println("hi"); 1+41 })
hi
x: Int = 84
scala>``````

actually , I think I understand it now. The first time it was touched it was evaluated and printed the hi. The next time it was called it just returns the result of the first evaluation, which is simply, 42. DUH

Possibly, you meant â€śdâ€™oh!â€ť Lazy semantics is often more â€śdâ€™oh!â€ť than â€śduhâ€ť.

Its purpose is to let the system figure out the order of evaluation.

1 Like

The result has nothing to do with laziness. Laziness only comes into play if you set b to false.

The lazy thing stores the value, or caches it , for a later evaluation. I think.
If you do not use â€ślazyâ€ť it will be evaluated twice; with lazy it is evaluated once.

Thatâ€™s just not true â€“ if you leave off the â€ślazyâ€ť, you get exactly the same result. (Try it.) Itâ€™s the `val` that causes the difference in behavior, by forcing the computation to happen once, when you evaluate that `val`; the fact that itâ€™s lazy is irrelevant.

Basically, the only thing that matters is how many times `i` is encountered in evaluating the function. Laziness doesnâ€™t change thatâ€¦

2 Likes

A good intuition is that a by-value (i.e., â€śnormalâ€ť) argument behaves like a `val` in the body of the method (itâ€™s evaluated once, before entering the method); and a by-name argument behaves like a `def` (itâ€™s evaluated each time its value is needed). Martin explains this very well in the Functional Programming Principles in Scala course on Coursera, which you might find useful.

1 Like

Actually lazy gets around the â€śevaluation every time it is neededâ€ť issue by caching the by-name object and thus, using it only once when it is called. If the lazy variable is called again it will only use the cached value. Paul Chiusano and RĂşnar Bjarnason explain it very thoroughly in the Book: Functional Programming In Scala. ( However, that book is not a fun book to read for a novice like myself; though I do like a challenge )

hmm maybe you are right. I will check that example again and see.

Here is a trace, also I added an additional function:
def maybeTwice(
b: Boolean,
i: => Int) = {
println(â€śhello 1 before usageâ€ť)
if (b) i + i else 0
}

def maybeTwice2(b: Boolean, i: => Int) = {
lazy val j = i
println(â€śhello 2 before usageâ€ť)
if (b) j + j else 0
}

def maybeTwice3(b: Boolean, i: => Int) = {
val j = i
println(â€śhello 3 before usageâ€ť)
if (b) j + j else 0
}

def main(args: Array[String]) {
var x = maybeTwice(true, { println(â€śhi 1â€ť); 1 + 41 })
println("=============")
x = maybeTwice2(true, { println(â€śhi 2â€ť); 1 + 41 })
println("=============")
x = maybeTwice3(true, { println(â€śhi 3â€ť); 1 + 41 })
//println("x = " + x)
}

observe the output carefully:

hello 2 before usage hi 2

hi 3
hello 3 before usage

Right, in fact @sidhartha11 you can test this by using `def j = i` instead of `val j = i`. It will print the output twice. In other words, the `lazy` is a red herring in that particular example.

Correct â€“ `lazy` affects the order of evaluation. But that has nothing to do with the fact that itâ€™s operating on a by-name parameter â€“ `lazy` will always do that.

Basically, youâ€™re observing two entirely separate phenomena. The by-name parameter means that it will be evaluated each time it is referenced, so you sometimes want to stick that in a `val` so that it only gets evaluated once. The `lazy` affects when (or indeed, if) the evaluation of its right-hand-side happens. But theyâ€™re independent effects, neither of which depends on the other, and itâ€™s very important to keep them straight.

I actually donâ€™t recall if Iâ€™ve ever used them together, although itâ€™s reasonable to do so â€“ itâ€™s a way of making sure that the by-name gets evaluated at most onceâ€¦

There is an issue for lazy params, i.e., a by-param that is assigned to a lazy val. Oh, I found it

Wow, that is one old issue. And yeah, it would be nice to haveâ€¦

The example comes from â€śFunctional Programming In Scalaâ€ť , It is a strange book to attempt to read; especially if you are a novice. However, I feel that the book is actually helping me slowly understand some of the unique aspects of functional programming in general; something that is really new to me. I only recommend that book to novices that have a joy of experiencing DEEP MENTAL PAIN.

Totally true ! laziness has nothing the do with the fact that the value is evaluated twice