Scala Tutorial
Basics
Control Statements
OOP Concepts
Parameterized - Type
Exceptions
Scala Annotation
Methods
String
Scala Packages
Scala Trait
Collections
Scala Options
Miscellaneous Topics
In Scala, function parameters can be passed in two main ways: call-by-value and call-by-name.
Call-by-value: This is the default mechanism. The function parameter values are computed before the function is called. Inside the function, the parameters refer to the pre-computed values, not the original arguments.
Call-by-name: In this method, the function parameter is not evaluated beforehand. Instead, it is evaluated every time it is used inside the function. It is similar to passing a block of code as a parameter.
To define a call-by-name parameter, you append =>
before the type of the parameter.
def printTwice(str: => String): Unit = { println(str) // Here, `str` is evaluated println(str) // Here, `str` is evaluated again } printTwice { println("Evaluating argument") "Hello" }
The output of the above code will be:
Evaluating argument Hello Evaluating argument Hello
The block of code provided to printTwice
gets evaluated twice, once for each time it's used inside the function. The string "Evaluating argument" is printed twice, demonstrating that the code block is evaluated each time str
is referenced.
Call-by-name can be particularly useful when:
Lazy Evaluation: You want to delay the evaluation of an expression until it's actually used. This can be efficient in cases where the expression might not always be needed.
Side Effects: If you want the side effects of an expression to be executed multiple times or in specific places within a function.
Control Structures: Scala uses call-by-name to implement control structures like if
, while
, etc., as library functions.
To see the difference, consider a call-by-value function:
def printTwiceValue(str: String): Unit = { println(str) println(str) } printTwiceValue { println("Evaluating argument") "Hello" }
The output will be:
Evaluating argument Hello Hello
The "Evaluating argument" is printed only once, indicating that the block was evaluated before being passed to the printTwiceValue
function.
In summary, call-by-name allows for lazy evaluation of function parameters in Scala, and it can be a powerful tool when used in the right scenarios.
Differences between Call-by-Name and Call-by-Value in Scala:
Call-by-name evaluates the passed expression every time it is used in the function body, while call-by-value evaluates the expression once before entering the function.
def callByValue(x: Int): Unit = { println("By Value: " + x) println("By Value: " + x) } def callByName(x: => Int): Unit = { println("By Name: " + x) println("By Name: " + x) }
Lazy Evaluation with Call-by-Name in Scala:
Call-by-name enables lazy evaluation, where the expression is evaluated only when needed.
def lazyPrint(condition: Boolean, message: => String): Unit = { if (condition) println(message) }
Benefits of Using Call-by-Name in Scala Functions:
Call-by-name is beneficial when the expression is not always needed, as it avoids unnecessary evaluations.
def logMessage(condition: Boolean, message: => String): Unit = { if (condition) println(message) }
Function Parameters and Call-by-Name in Scala Closures:
Call-by-name can be particularly useful in closures, allowing dynamic evaluation of expressions.
def closureExample(x: Int, f: => Int => Int): Int = { f(x) } val result = closureExample(5, _ * 2)
Practical Examples of Call-by-Name in Scala:
Use call-by-name in scenarios where lazy evaluation is desirable, or expressions should be conditionally evaluated.
def ifTrue(condition: Boolean, trueBranch: => String, falseBranch: => String): String = { if (condition) trueBranch else falseBranch }