There are already lots of fantastic answers for this question in Internet. I will write a compilation of several explanations and examples I have gathered about the topic, just in case someone may find it helpful
INTRODUCTION
call-by-value (CBV)
Typically, parameters to functions are call-by-value parameters; that is, the parameters are evaluated left to right to determine their value before the function itself is evaluated
def first(a: Int, b: Int): Int = a
first(3 + 4, 5 + 6) // will be reduced to first(7, 5 + 6), then first(7, 11), and then 7
call-by-name (CBN)
But what if we need to write a function that accepts as a parameter an expression that we don't to evaluate until it's called within our function? For this circumstance, Scala offers call-by-name parameters. Meaning the parameter is passed into the function as it is, and its valuation takes place after substitution
def first1(a: Int, b: => Int): Int = a
first1(3 + 4, 5 + 6) // will be reduced to (3 + 4) and then to 7
A call-by-name mechanism passes a code block to the call and each time the call accesses the parameter, the code block is executed and the value is calculated. In the following example, delayed prints a message demonstrating that the method has been entered. Next, delayed prints a message with its value. Finally, delayed returns ‘t’:
object Demo {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("Getting time in nano seconds")
System.nanoTime
}
def delayed( t: => Long ) = {
println("In delayed method")
println("Param: " + t)
}
}
In delayed method
Getting time in nano seconds
Param: 2027245119786400
PROS AND CONS FOR EACH CASE
CBN:
+Terminates more often * check below above termination *
+ Has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body
-It is slower, it creates more classes (meaning the program takes longer to load) and it consumes more memory.
CBV:
+ It is often exponentially more efficient than CBN, because it avoids this repeated recomputation of arguments expressions that call by name entails. It evaluates every function argument only once
+ It plays much nicer with imperative effects and side effects, because you tend to know much better when expressions will be evaluated.
-It may lead to a loop during its parameters evaluation * check below above termination *
What if termination is not guaranteed?
-If CBV evaluation of an expression e terminates, then CBN evaluation of e terminates too
-The other direction is not true
Non-termination example
def first(x:Int, y:Int)=x
Consider the expression first(1,loop)
CBN: first(1,loop) → 1
CBV: first(1,loop) → reduce arguments of this expression. Since one is a loop, it reduce arguments infinivly. It doesn’t terminate
DIFFERENCES IN EACH CASE BEHAVIOUR
Let's define a method test that will be
Def test(x:Int, y:Int) = x * x //for call-by-value
Def test(x: => Int, y: => Int) = x * x //for call-by-name
Case1 test(2,3)
test(2,3) → 2*2 → 4
Since we start with already evaluated arguments it will be the same amount of steps for call-by-value and call-by-name
Case2 test(3+4,8)
call-by-value: test(3+4,8) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7 * (3+4) → 7 * 7 → 49
In this case call-by-value performs less steps
Case3 test(7, 2*4)
call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (7)*(7) → 49
We avoid the unnecessary computation of the second argument
Case4 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
Different approach
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. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.
EXAMPLES WHERE IT IS BETTER TO USE CALL-BY-NAME
From: https://mcmap.net/q/111318/-when-to-use-call-by-name-and-call-by-value
Simple performance example: logging.
Let's imagine an interface like this:
trait Logger {
def info(msg: => String)
def warn(msg: => String)
def error(msg: => String)
}
And then used like this:
logger.info("Time spent on X: " + computeTimeSpent)
If the info method doesn't do anything (because, say, the logging level was configured for higher than that), then computeTimeSpent never gets called, saving time. This happens a lot with loggers, where one often sees string manipulation which can be expensive relative to the tasks being logged.
Correctness example: logic operators.
You have probably seen code like this:
if (ref != null && ref.isSomething)
Imagine you would declare && method like this:
trait Boolean {
def &&(other: Boolean): Boolean
}
then, whenever ref is null, you'll get an error because isSomething will be called on a nullreference before being passed to &&. For this reason, the actual declaration is:
trait Boolean {
def &&(other: => Boolean): Boolean =
if (this) this else other
}