Partial function application launches code block prematurely when underlined

Given:

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

I can call him:

 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 a curious behavior with partial application:

 save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected save(throw new RuntimeException("boom!")) _ -> exception thrown 

The code block is immediately evaluated without passing as a function. What is the difference between the above 2 statements?

+7
source share
2 answers

First case

 save(throw new RuntimeException("boom!")) _ 

According to the โ€œScala Linkโ€ (ยง6.7), an underscore is used instead of the argument list, and the expression is converted to

 val f: (Boolean) => Unit = save(throw new RuntimeException("boom!")) 

where the first def save argument is immediately evaluated.

The expression e_ is well-formed if e is of a method type or if e is a call-by-name. If e is a method with parameters, e_ represents e is converted to a function type by eta extension (ยง6.26.5). If e is a parameterless method or a call by name is a parameter of type => T, e_ represents a function of type () => T, which evaluates e when it is applied to empty parameterlist ().

In order for everything to work as you expect, some changes are needed:

 scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") } save: (f: () => Any)(run: Boolean)Unit scala> val f = save(() => throw new RuntimeException("boom!")) _ f: (Boolean) => Unit = <function1> scala> f(true) running f java.lang.RuntimeException: boom! at $anonfun$1.apply(<console>:6) 

Second case

 save(throw new RuntimeException("boom!"))(_) 

According to the โ€œScala Linkโ€ (ยง6.23), when a placeholder is used as a substitute for an argument, the expression is converted to

 val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_) 
+2
source

Currently, the behavior of parameters by the same name is considered under the eta extension, see this error . Your code works as you expect (i.e. the string save(throw new RuntimeException("boom!")) _ Returns a function without exception) with recent nightly builds in 2.10. See if he will stay until release!

See also this question on the corresponding question about the general case of the eta extension that does not include calling by name.

0
source

All Articles