Is there a way to call a function defined using `val` in Scala with the whole curly brace block as an argument and not the final result of that block?

Viewed 191

I know that if we want to pass a block of code in curly braces as an argument to functions defined using def, we can write:

def run(func: => Unit) {
   func
}
run {
    print(1)
    println(2)
} // prints 12

But is there a way to achieve the same style with an anonymous function? I have tried the following:

val v: (()=>Unit) => Unit = ( w: ()=> Unit) => { w() }
v( () => { println(1); println(2) } ) // Works as expected. Prints 12
v { println(1); println(2) } // error: type mismatch

Correction:

()=>Unit doesn't translate to a function that has a by-name parameter which would allow it to accept code enclosed by curly braces as a parameter. So my question's second part was incorrect.

Alexey Romanov's answer works perfectly if we don't re-specify the argument type in function literal, but if we re-specify the argument type in the function literal which matches the type of variable exactly, it is seen as an error. For example, if we write

val v: (=>Unit) => Unit = (w) => { println(0); w } // works
val v: (=>Unit) => Unit = (w:=>Unit) => { println(0); w } // error

val v: (Int => Int) = (w) => 43   // works
val v: (Int => Int) = (w:Int) => 43  // works as well
2 Answers
val v: (=>Unit) => Unit = w => { println(0); w }

v { println(1); println(2) }

println(0) inserted purely so you can see this is really a by-name parameter: 0 is printed before 1 and 2.

The pattern block :=> Type is called by-name parameter and does not have to be a function but can be any block of code that evaluated to the type Type. That's why the first example works.

The second part does not work because the passed argument:

println(1); println(2)

evaluates to Unit and does not match the expected type ()=>Unit.

Related