Multiline function literal as arguments in Scala

altcoder picture altcoder · Dec 14, 2012 · Viewed 13k times · Source

I always wondered why sometimes with function literals we can ignore the curly brace even for multiple statements. To illustrate this, the syntax for a multiline function literal is to enclose the statements with curly braces. Like so,

val fl = (x: Int) => {
  println("Add 25 to "+x)
  x + 25
}

However, when you pass it to a single-argument function, you can ignore the required curly brace for the function literal.

So for a given function f,

def f( fl: Int => Int ) {
  println("Result is "+ fl(5))
}

You can call f() like this,

f( x=> {
  println("Add 25 to "+x)
  x + 25
})
-------------------------
Add 25 to 5
Result: 30

Or when you use curly braces instead of parenthesis in the function call, you can remove the inner curly braces from the function literal. So the following code will also work,

f{ x=>
  println("Add 25 to "+x)
  x + 25
}

The above code is more readable and I notice that a lot of examples use this syntax. However, is there any special rule that I may have missed, to explain why this is working as intended?

Answer

som-snytt picture som-snytt · Dec 14, 2012

There are just a couple of simple syntax rules. The appendix of the spec is worth perusing.

A function literal or anonymous function (6.23) will look like x => Expr or x => Block depending on whether the context is an Expr or a ResultExpr, respectively.

A function application (6.6) will look like f(Expr, Expr) or f BlockExpr, i.e., f{ Block }. That is, a BlockExpr is just a sequence of block statements inside {...}.

When you call f(g), then g is an Expr, so as a function literal, x => Expr. The Expr can be a BlockExpr, x => { ... }.

When you call f{ Block }, then f { x => ... } has the function literal in ResultExpr of a Block (which is just a sequence of statements, no braces required).

Here, it's obvious that the anon func is at the bottom of a block:

scala> def m(x: Int=>Int) = x(5)
m: (x: Int => Int)Int

scala> m {
     | val y = 7
     | x => // no brace
     | x+y+1
     | }
res0: Int = 13