1. Overview

In this tutorial, we’ll learn about the features and evaluation strategies of call by-value and call by-name in Scala and how we can use them in practice.

2. Call By-Value

Function arguments are considered call by-value by default in Scala. Let’s define a function, test, which takes an argument as call by-value:

def test(a: Int) = a * a

In general, applications of parameterized functions are evaluated similarly as operators. First, it evaluates all the function arguments, from left to right. Then it replaces the function application by the function’s right-hand side, and, at the same time, it replaces the formal parameters of the function by the actual arguments. The call by-value strategy has the advantage that it evaluates every function argument only once.

3. Call By-Name

To make an argument called by-name, we simply prepend => (rocket symbol) to its type.

Let’s define a function, test, which takes an argument as call by-name:

def test(a: => Int) = a * a

Call by-name evaluation is similar to call by-value, but it has the advantage that a function argument won’t be evaluated until the corresponding value is used inside the function body.

Both strategies are reduced to the final value as long as:

  • The reduced expression consists of pure functions
  • Both evaluations terminate

4. Examples

Let’s define a function, addFirst, which takes an argument x of type Int as a call by-value and an argument y of type Int as a call by-name:

def addFirst(x: Int, y: => Int) = x + x

Now, let’s understand the evaluation of the function addFirst as a call by-value:

assert(addFirst(3+5, 7) == 16)

In this case, the call by-value strategy will first evaluate the expression 3+5 and then pass the value 8 to the function’s body where x parameter is added to itself to evaluate the final value of 16.

Now, let’s look at the same example as a call by-name.

assert(addFirst(7, 3+5) == 14)

In case, the call by-name strategy will ignore expression 3+5 because parameter y is not used inside the function’s body. Therefore, the parameter x will be added to itself producing the final value of 14.

In this example, the call by-name strategy is one step faster than the call by-value strategy.

Now, let’s take one more example. Let’s define an infinitely recursive function infinite():

def infinite(): Int = 1 + infinite()

If we apply this function as the x parameter in addFirst, the call by-value argument will produce a StackOverflowError:

assertThrows[StackOverflowError] {
  addFirst(infinite(), 4)
}

In the above example, simply calling the function produced a StackOverflowError because infinite() is evaluated before the function body is evaluated.

Now, if we use infinite() as the call by-name argument:

assert(addFirst(4, infinite()) == 8)

The infinite() function is never evaluated in the function body. Therefore, the function call runs successfully.

5. Call By-Value or Call By-Name

Using call by-name may seem like a more efficient solution since it’s possible that the argument is not evaluated.

However, call by-value is often more efficient than call by-name because it avoids the repeated re-computation of argument expressions that call by-name entails. Additionally, it can avoid other side effects because we know when the expressions will be evaluated.

6. Conclusion

In this tutorial, we introduced call by-value and call by-name in Scala. We’ve seen some of their features, usage, and evaluation strategies. As usual, the full source code can be found over on GitHub.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.