Skip to content

Instantly share code, notes, and snippets.

@stumash
Last active February 3, 2021 09:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stumash/26c72f115d04a994775e3ab1ecfdcbd3 to your computer and use it in GitHub Desktop.
Save stumash/26c72f115d04a994775e3ab1ecfdcbd3 to your computer and use it in GitHub Desktop.
by-name function calls in scala
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