def getStr(): String = {
println("getStr is running")
"str"
}
def lazyHello(para: => String) = {
println("lazy hello is runing")
println(para)
}
def notLazyHello(para: String) = {
println("not lazy hello is runing")
println(para)
}
def anoyHello(para: () => String) = {
println("anoy hello is runing")
println(para())
}
notLazyHello(getStr)
lazyHello(getStr)
anoyHello(getStr)
got this result:
scala> notLazyHello(getStr)
getStr is running
not lazy hello is runing
str
scala> lazyHello(getStr)
lazy hello is runing
getStr is running
str
scala> anoyHello(getStr)
anoy hello is runing
getStr is running
str
seems like lazyHello and anoyHello perform the same.
So, in Scala, when would be a good time to use lazily evaluated parameter rather than to use a function as a parameter?
Your observation is correct. lazyHello
and anoyHello
are in fact the same. This is because para: => String
is shorthand for para: () => String
.
Another way to look at this:
() => String
is a function that takes no parameters and returns a string.
=> String
is something that evaluates to a string, without taking parameters. So essentially call-by-name is a function without an input parameter.
Basically there's no technical difference between lazy evaluated parameter and Function0
parameter. There are pro's and cons of both the implementation.
Function0
parameter is definitely verbose. So if you change them to lazy parameter, code will become much readable.
Here is a bug prone situation of lazy evaluation.
Consider following code
def inner = println("inner called")
def execute(f: => Unit) = {
println("executing")
f
}
def redirect(f: => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// executing
// inner called
Now think for some reason you forget to put =>
in the execute function. Code will compile correctly, but the behavior will be different and might introduce bugs.
def execute(f: Unit) = {
println("executing")
f
}
def redirect(f: => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// inner called
// executing
But if you use Function0
, the code will not compile. So, the Function0
parameters are less bug prone.
def inner() = println("inner called")
def execute(f:() => Unit) = {
println("executing")
f()
}
def redirect(f:() => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// executing
// inner called
=========================================
def inner() = println("inner called")
def execute(f:Unit) = {
println("executing")
f
}
def redirect(f:() => Unit) = {
println("redirecting")
execute(f) // Will not compile.
}
Furthermore, You can clearly see when that value is evaluated.
Anyway if you are so sure what you do, you can use any one of them. Decision is yous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With