This is called a by name parameter, as related to call-by-name parameter evaluation strategy. Please see the linked wikipedia article for similar, but not identical, ways of passing parameters.
To explain it better, let's consider first the two most common parameter evaluation strategies: call by value and call by reference.
Call by value is by far the most common evaluation strategy. It is the sole strategy in Java, for instance, and the default strategy in C. Consider, for instance, this simple Java program:
public class ByValue { static public void inc(int y) { y++; } static public void main(String... args) { int x = 0; inc(x); System.out.println(x); } }
It will print 0, because x's value is copied to y, so that when y is incremented it doesn't change the original value in x. Contrast this with this C++ program with call-by-reference:
#include <stdio.h> void inc(int &y) { y++; } int main() { int x = 0; inc(x); printf("%d\n", x); }
This will print 1, because the reference to x is passed to inc, instead of x's value.
Note that Java passes objects references by value, which leads some to claim it does call by reference. This is not true, to the extent that if you were to assign a new object to a parameter of a function, it would not be reflected in the function's caller.
So, what does a call by name looks like? In a call by name, neither value nor reference is passed. Instead, the whole code is passed, and everywhere the parameter is used, the code is executed and its result used. For example:
object ByName { def incIfZero(y: => Int): Int = if (y == 0) y + 1 else y def main(args: Array[String]) { var x = 0 x = incIfZero( { val tmp = x; x += 1; tmp } ) println(x) } }
This example prints 2 instead of 1, because the block of code passed as parameter is evaluted twice. When executing, it's as if the second line in the main was written like this:
x = if ({ val tmp = x; x += 1; tmp }) { val tmp = x; x += 1; tmp } + 1 else { val tmp = x; x += 1; tmp }
Now, by name parameters have at least three interesting uses:
- It can be used to delay the execution of something until the proper time.
- It can be used to avoid the execution in some situations.
- It can be used to execute some block of code multiple times.
The first and last cases are pretty obvious, I think. Here's an example of the second case:
implicit def fromBoolean(b: Boolean) = new { def and(that: => Boolean): Boolean = if (b) that else b } val x = 0 (x > 0) and (10 / x > 0)
If that was not a by name parameter, there would be an exception thrown at the last line. As it is, it will just return false.