Last active
February 3, 2021 09:16
-
-
Save stumash/26c72f115d04a994775e3ab1ecfdcbd3 to your computer and use it in GitHub Desktop.
by-name function calls in scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object ByName { | |
/** | |
* So-called 'by name' function parameters are basically automatically wrapped in thunks | |
* | |
* how 'by name' function are desugared: | |
* | |
* def f(x: => Int): Int = { x; x } | |
* f( { println("once"); 1 } ) | |
* | |
* desugars to | |
* | |
* def f(x: Unit => Int): Int = { x(); x() } | |
* f( () => { prlntln("once"); 1 } ) | |
*/ | |
def main(args: Array[String]): Unit = { | |
basicUseCase() | |
nested() | |
} | |
def basicUseCase(): Unit = { | |
var oneToTen = (1 to 10).iterator | |
def useItByValue(x: Int): Unit = { | |
println(s"x: $x, x again: $x") | |
} | |
oneToTen = (1 to 10).iterator | |
useItByValue(oneToTen.next()) // "x: 1, x again: 1" | |
// next() is called once, and the return value is passed in | |
def useItByName(x: => Int): Unit = { | |
println(s"x: $x, x again: $x") | |
} | |
oneToTen = (1 to 10).iterator | |
useItByName(oneToTen.next()) // "x: 1, x again: 2" | |
// next() is called twice. it's called each time the variable x is evaluated | |
def useItByName2(x: => Int): Unit = { | |
val y = x | |
println(s"x: $y, x again: $y") | |
} | |
oneToTen = (1 to 10).iterator | |
useItByName2(oneToTen.next()) // "x: 1, x again: 1" | |
// next() is called once, when x is evaluated on assignment to y | |
} | |
def nested(): Unit = { | |
def inner(y: => Int): Int = y | |
def outer(x: => Int): Int = inner(x) | |
val oneToTen = (1 to 10).iterator | |
println(outer(oneToTen.next())) // 1 | |
// the by-name parameter only gets evaluated once, the return value of inner() | |
// desugared and evaluated like so | |
// | |
// outer(oneToTen.next()) | |
// desugars to | |
// outer(x = () => { oneToTen.next() }) | |
// evaluates to | |
// inner(x()) | |
// desugars to | |
// inner(y = () => { x() }) | |
// evaluates to | |
// y() | |
// evaluates to | |
// x() | |
// evaluates to | |
// oneToTen.next() | |
// evaluates to | |
// 1 | |
// | |
// keep in mind the desugaring happens at compile-time, and the evaluation happens at runtime | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment