Scala - Parentheses and Curly Brackets in Anonymous Functions

Scala gives a lot of flexibility in defining anonymous functions, and that might lead to a confussion. Jacek Laskowski asked an interesting question on  stackoverflow.com regarding of calling a map method on collection. To summarize it (given a list lst):

Why  lst map {c:Char => 1}  and  lst map ((c:Char) => 1)  work fine, but  lst map (c:Char => 1)  gives us compilation error:

 error: identifier expected but integer literal found.
       lst map (c:Char => 1)


To answer this question we should look into  Scala Language Specification , into part  6.23 Anonymous Functions .There is a description how anonymous function can be defined:

Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
ResultExpr ::= (Bindings | ([‘implicit’] id | ‘_’) ‘:’ CompoundType) ‘=>’ Block
Bindings ::= ‘(’ Binding {‘,’ Binding} ‘)’
Binding ::= (id | ‘_’) [‘:’ Type]

As you can see Bindings requires to be placed inside two surrounding parentheses. So if anonymous function defines the type of the parameter, as in our example, it has to be defined in this way:

(c:Char)=>1

?

And the call to map should look like that: 

lst map((c:Char)=>1)

?
Also in the same part of reference documentation we can find:

If an anonymous function  (x: T) => e with a single typed parameter appears as the result expression of a block, it can be abbreviated to  x: T => e

So if anonymous function is defied as last expression in a code block, and has exacly one parameter, you can use abbreviated syntax, without parenthesis aroundc:Char, to define anonymous function. So, in our example, we can write c:Char => 1, but only when we place it inside a code block {c:Char => 1}. And we can call map function this way:

lst map({c:Char=>1})

?

or with abbreviated syntax without parenthesis:

lst map {c:Char=>1}

?
And that explains main question why  lst map {c:Char => 1}  is legal, and  lst map (c:Char => 1)  is not.

This is summarized in changelog at the end of the documentation (Changes in Version 2.1.7 (19-Jul-2006)):

Closure Syntax

The syntax of closures has been slightly restricted (§6.23). The form

x: T => E

is valid only when enclosed in braces, i.e. { x: T => E }. The following is illegal, because it might be read as the value x typed with the type T => E:

val f = x: T => E

Legal alternatives are:

val f = { x: T => E }
val f = (x: T) => E


Another way to specify anonymous functions:

If we look closer at specification we can see that it allows us to use another way to define anonymous function:

Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr

We can see that we can define your anonymous function without parameter binding in those two ways (if we don't need to specify argument type):

lst map (c =>1)
// or
lst map (_=>1)

I hope that this article clarified how we can declare anonymous functions and it shouldn't cause a confusion any more.


-------------------------------------------------------

In general, there are many cases when you would prefer curly braces (e.g. multiline expressions, for comprehensions), but let's talk specifically about

when it's written on a single line, is there any inherent reason to use one over the other

In a second case it's not just curly braces, instead of parentheses, it's curly braces with ommited parentheses. Scala allows you to ommit parenthesis sometimes, and the later syntax is used to access to the niceties you got in partial functions (namely, pattern matching), so

lst foreach {x => println(s"you get the idea, $x")}

is actually

lst foreach({x => println(s"you get the idea, $x")})

which, as I said, can be useful from pattern matching POV:

val map = Map("foo" -> "bar")
map foreach { case (k, v) => println(s"key: $k, value: $v") }
// which is not possible with the usual parenthesis
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值