How to Call by Value vs Call by Name in Scala
- Call by Value in Scala
- Call by Name in Scala
- Call by Value vs. Call by Name Strategies in Scala
- Conclusion
In this article, we will learn about call-by-value and call-by-name features and their evaluation strategies in Scala. And we will discuss how to use them in practice.
Call by Value in Scala
Function arguments in Scala are, by default, considered call-by-value. Let us see a small example:
def example(x:Int) = x*x
In the above code, we have defined a function example
that takes an argument as a call by value.
Generally, just like operators in Scala, parameterized functions are evaluated in the same manner by the compiler. First, all the function arguments are evaluated from left to right; then, all the function applications are replaced by the function’s right-hand side.
Simultaneously, all the function’s formal parameters are replaced by the actual parameters.
One big advantage of the call-by-value strategy is that every function argument is evaluated only once.
Call by Name in Scala
We only prepend =>
(equal to and greater than symbol) to the function arguments to make the argument call by name.
Let’s see a small example to understand it better:
def example(x: =>Int) = x*x
The parameter x
in the above code is called by value. Though the call-by-name evaluation is the same as the call-by-value strategy, it has one major advantage: the function will not be evaluated until its corresponding value is used inside the function body.
Call by Value vs. Call by Name Strategies in Scala
Let’s say we have a function add
with two parameters: x
, which is of type int and called by value, and y
, which is of type int and called by name.
def add(x: Int, y:=>Int) = x+x
Let us see how the add
function is evaluated using the call-by-value strategy.
assert(add(3+3,8) == 12)
Here, the call-by-value first evaluates the expression 3+3
and then passes the value 6
to the function’s body. The parameter x
is added to itself to calculate the final answer as 12
.
Now, let’s see the same function evaluated using the call-by-name strategy.
assert(add(8,3+3) == 16)
In this case, 3+3
is ignored by the call-by-name strategy because the parameter y
is never used inside the function’s body. Hence, the x
is added to itself to calculate the final answer as 16
.
We can say that the call-by-name strategy is a little faster than the call-by-value strategy in this case.
Let us see one more example, where we have a function that recursively calls itself infinitely.
def myFun(): Int = myFun() + 1
Now, if we use this function as parameter x
in our add
function, then the call by value
argument x
will give StackOverflowError
.
assertThrows[StackOverflowError]
{
add(myFun(),5)
}
In the above code, calling the function gives StackOverflowError
because the myFun()
method is evaluated before its function body. In contrast, if we use the myFun
method as a call-by-name argument, the function call runs successfully without throwing any exception because it will never be evaluated inside the function body.
assert(add(5, myFun()) == 10)
the Better One to Use in Our Code
Based on the above examples, the call-by-name strategy seems more appealing as it is more efficient as there are chances that the passed argument might never be evaluated inside the function body.
But, if we see holistically, the call-by-value strategy is more efficient than the call-by-name as repeated computation of arguments is avoided in it. In addition, the side effects can be avoided as we know when the arguments will be evaluated in the code.
Conclusion
In this article, we learned about Scala’s call-by-name and call-by-value strategies. We’ve learned how they are evaluated and seen their usage, concluding that the call-by-value strategy is better to use in most cases.