Reputation: 41909
Given:
def higherOrderCallByName(f: => Int => Int, x: Int): Int = f(x)
def higherOrderCallByValue(f: Int => Int, x: Int): Int = f(x)
under what circumstances is it idiomatic/proper to use call by-name for a a function argument, i.e f
in higherOrderCallByName
?
Upvotes: 2
Views: 339
Reputation: 4256
Just to clarify, in call-by-value, the value of the parameter is determined before it is passed to the function, while in call-by-name evaluation of the parameter is deferred until it is used inside the function.
I concur with m-z, higherOrderCallByName
is perfectly valid where passed function can be an expensive call.
Another scenario I can think of is, if passed function has some side effect then by-name parameter will behave differently than by-value parameter. I have modified your example to demonstrate this:
def higherOrderCallByName(f: => Int => Int, x: Int): Int = {
println("Inside by-name function.")
f(x)
}
def higherOrderCallByValue(f: Int => Int, x: Int): Int = {
println("Inside by-value function.")
f(x)
}
def funWithSideEffect() : (Int) => Int = {
println("Some side effect.") // some side-effect or some expensive call
x => x + 1 // returns function which increments param
}
Now if you call higherOrderCallByValue(funWithSideEffect(), 2)
output will be:
Some side effect.
Inside by-value function.
As output suggests, side-effect occurs before higherOrderCallByValue
's body executes.
Whereas output of higherOrderCallByName(funWithSideEffect(), 2)
will be like:
Inside by-name function.
Some side effect.
Where side-effect occurs inside higherOrderCallByName
when f(x)
is encountered. Now imagine the scenario where f(x)
is executed multiple times inside higherOrderCallByName
. Clearly it would have lot of impact in your application.
Upvotes: 3