Given:
def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") }
I can call it with:
save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown
Here's the curious behaviour with partial application:
save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown
The codeblock is evaluated immediately without being passed in as a function. What is the difference between the above 2 statements?
First case,
According to "Scala Reference" (§6.7), trailing underscore is used in place of the argument list, and expression is converted to
where the first argument of
def save
is immediately evaluated.To make the things work as you expect, some modifications are required:
Second case,
According to "Scala Reference" (§6.23), when placeholder is used as a replacement for an argument, the expression is converted to
The behaviour of call-by-name parameters under eta expansion is currently under review, see this bug. Your code works as you expect (that is, the line
save(throw new RuntimeException("boom!")) _
returns a function without throwing the exception) with recent nightly builds of 2.10. Let's see if it stays in until release!See also this question for a related question on the general case of eta expansion not involving call-by-name.