First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int
.
def something() = {
println("calling something")
1 // return value
}
Now we are going to define two function that accept Int
arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int
) and the other in a call-by-name style (x: => Int
).
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
Now what happens when we call them with our side-effecting function?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()
) only happened once. However, in the call-by-name version, the side-effect happened twice.
This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. Instead, call-by-name functions recompute the passed-in expression's value every time it is accessed.
Another Example:
Imagine you want to build a "nagger app" that will Nag you every time since time last you got nagged.
Examine the following implementations:
object main {
def main(args: Array[String]) {
def onTime(time: Long) {
while(time != time) println("Time to Nag!")
println("no nags for you!")
}
def onRealtime(time: => Long) {
while(time != time) println("Realtime Nagging executed!")
}
onTime(System.nanoTime())
onRealtime(System.nanoTime())
}
}
In the above implementation the nagger will work only when passing by name the reason is that, when passing by value it will re-used and therefore the value will not be re-evaluated while when passing by name the value will be re-evaluated every time the variables is accessed
No comments:
Post a Comment