Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Omitting parenthesis

Tags:

scala

Here is Scala code

 #1
 def method1 = {
   map1.foreach({
    case(key, value) => { println("key " + key + " value " + value) }
   })
}

 #2
 def method1 = {
   map1.foreach{
    case(key, value) => { println("key " + key + " value " + value) }
   }
}

It almost figures for me, but nevertheless I want to make it clearer: why is it possible to omit parenthesis in this case?

like image 473
Alan Coromano Avatar asked Jun 20 '13 10:06

Alan Coromano


1 Answers

You can always exchange methods argument parentheses for curly braces in Scala. For example

def test(i: Int) {}

test { 3 }

The base for this is the definition of argument expressions, covered by section §6.6 of the Scala Language Specification (SLS):

ArgumentExprs ::= ‘(’ [Exprs] ‘)’
                | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ’)’
                | [nl] BlockExpr

The curly braces are covered by the last case (block expression), which essentially is ‘{’ Block ‘}’ (cf. beginning of chapter 6 SLS).

This doesn't go for conditional expressions, if, (§6.16 SLS) and while loop expressions (§6.17 SLS), but it works for for comprehensions (§6.19 SLS), somewhat of an inconsistency.

A pattern matching statement or pattern matching anonymous functions literal on the other hand must be defined with curly braces, e.g. { case i: Int => i + i }, parentheses are not allowed here (§8.5 SLS).

In your method call, foreach takes a function argument, so you can drop the redundant parentheses or double braces:

List(1, 2).foreach({ case i => println(i) })
List(1, 2).foreach {{ case i => println(i) }}

List(1, 2).foreach { case i => println(i) }  // no reason to have double braces

In this case, the pattern matching doesn't really buy you anything, and you can use a regular (non-pattern-matching) function, and thus the following would work, too:

List(1, 2).foreach(i => println(i)) // §6.23 SLS - anonymous functions
List(1, 2).foreach(println)         // §6.26.2 / §6.26.5 - eta expansion

In your case though, a Map's map method passes a tuple of key and value to the function, that's why you use pattern matching (case statements) to deconstruct that tuple, so you are bound to have curly braces. That is nicer than writing

map1.foreach(tup => println("key " + tup._1 + " value " + tup._2)

As a side note, putting braces around pattern matching case bodies is considered bad style; they are not necessary, even if the body spans multiple lines. So instead of

case(key, value) => { println("key " + key + " value " + value) }

you should write

case (key, value) => println("key " + key + " value " + value)

There is a bit of polemic in this blog post regarding the different variants of using braces, dots and parentheses in Scala (section "What's not to like"). In the end, you are to decide which is the best style—this is where people advocating "opinionated" versus "un-opinionated" languages fight with each other.

In general, you need curly braces when the expression spans multiple lines or if you have a pattern match. When calling methods with multiple parameter lists, often the last list contains one function argument, so you get nice looking—subjective judgment of course—syntax:

val l = List(1, 2, 3)
l.foldLeft(0) {
  (sum, i) => sum + i
}
like image 76
0__ Avatar answered Oct 20 '22 00:10

0__