Call by name vs call by value in Scala, clarification needed

The example you have given only uses call-by-value, so I will give a new, simpler, example that shows the difference.

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.


Here is an example from Martin Odersky:

def test (x:Int, y: Int)= x*x

We want to examine the evaluation strategy and determine which one is faster (less steps) in these conditions:

test (2,3)

call by value: test(2,3) -> 2*2 -> 4
call by name: test(2,3) -> 2*2 -> 4
Here the result is reached with the same number of steps.

test (3+4,8)

call by value: test (7,8) -> 7*7 -> 49
call by name: (3+4) (3+4) -> 7(3+4)-> 7*7 ->49
Here call by value is faster.

test (7,2*4)

call by value: test(7,8) -> 7*7 -> 49
call by name: 7 * 7 -> 49
Here call by name is faster

test (3+4, 2*4) 

call by value: test(7,2*4) -> test(7, 8) -> 7*7 -> 49
call by name: (3+4)(3+4) -> 7(3+4) -> 7*7 -> 49
The result is reached within the same steps.


In the case of your example all the parameters will be evaluated before it's called in the function , as you're only defining them by value. If you want to define your parameters by name you should pass a code block:

def f(x: => Int, y:Int) = x

This way the parameter x will not be evaluated until it's called in the function.

This little post here explains this nicely too.


To iteratate @Ben's point in the above comments, I think it's best to think of "call-by-name" as just syntactic sugar. The parser just wraps the expressions in anonymous functions, so that they can be called at a later point, when they are used.

In effect, instead of defining

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

and running:

scala> callByName(something())
calling something
x1=1
calling something
x2=1

You could also write:

def callAlsoByName(x: () => Int) = {
  println("x1=" + x())
  println("x2=" + x())
}

And run it as follows for the same effect:

callAlsoByName(() => {something()})

calling something
x1=1
calling something
x2=1

I will try to explain by a simple use case rather than by just providing an 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