5

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?

Alan Coromano
  • 24,958
  • 53
  • 135
  • 205

1 Answers1

5

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
}
0__
  • 66,707
  • 21
  • 171
  • 266
  • I guess the question is why this works: `List(1).map {_+1}`, but `List(1).map f` and `List(1).map( case i => i )` - not. – senia Jun 20 '13 at 12:01
  • @senia The former case is covered by the argument expression being a block statement. The second case is invalid, because you are trying to do a "halfway" infix operator call (see again chapter 6 SLS). An infix expression is `InfixExpr id [nl] InfixExpr`, so you cannot have a period here. `List(1) map f` is a valid infix call. – 0__ Jun 20 '13 at 12:35
  • If braces are part of function literal than the former case and the second case are equal. If braces are replacement for parenthesis then the former case and the third case are equal. So which is it? In fact in this case braces are replacement for parenthesis **and** functional literal parsing is not context independent. So `{case i => i}` equals to `{f}` (while `( case i => i)` not equals to `(f)`). But I can't find corresponding documentation. – senia Jun 20 '13 at 12:43
  • `f` is not a function _literal_. It might be a _value_ holding a function. That's not the same. In `val i = 3`, `3` is a literal, but `i` is a value. A Ford Mustang is a car, but not every car is a Mustang. An argument expression may use a block expression. But a pattern matching literal must always use curly braces. Therefore the third case is invalid. `{case i => i}` is a pattern matching literal, `{f}` is not (again, `f` is a value). – 0__ Jun 20 '13 at 12:49
  • If `{case i => i}` is a pattern matching literal, then this is a call of method `map` without braces or parenthesis: `List(1).map {case i => i}` since the only pair of braces here is the part of function literal. But you can't call method `map` with don and without braces or parenthesis: `List(1).map f`. There should be no difference here between value and function literal. In the AST level both are `Expr[A => B]`. – senia Jun 20 '13 at 13:05
  • "with dot". "with don" is a typo. – senia Jun 20 '13 at 13:11
  • You don't want to give up, eh? Please, do read the SLS. p74: A `BlockExpr` is _either_ `‘{’ CaseClauses ‘}’` _or_ `‘{’ Block ‘}’`. So a pattern matching literal qualities as a block expression, and therefore qualifies as an argument expression, and therefore no need to sprinkle around more braces and popcorn. – 0__ Jun 20 '13 at 13:12
  • 1
    Thank you! I thought that `ArgumentExprs` is defined like `‘(’ [Exprs] ‘)’ | ‘{’ Expr ‘}’`, but it's like `‘(’ [Exprs] ‘)’ | BlockExpr`. Now it's all clear to me. – senia Jun 20 '13 at 13:29
  • why can't I say `map1.foreach((key, vaue) =>...)`? -- `(key, vaue)` is still one argument, is not that so? – Alan Coromano Jun 20 '13 at 13:53
  • `(key, value) => ...` is a function with _two_ arguments. Here `foreach` takes a `Function1[(A, B), Unit]` and not a `Function2[A, B, Unit]`. So it takes one tuple argument. Using the pattern matching, you can deconstruct that tuple which makes it look like a `Function2` except for the `case` keyword. The reason is that `foreach` is defined on a general collection, `Iterable[X]`—so `def foreach(f: X => Unit)`—, and since `Map[A, B] extends Iterable[(A, B)]`, it becomes `foreach(fun: ((A,B)) => Unit)` for maps. Otherwise, using a `Function2` would certainly have been the more natural choice. – 0__ Jun 20 '13 at 14:11
  • Cf. http://stackoverflow.com/questions/17109855/scala-strange-implicit-boxing-conversion-error/17110036 – 0__ Jun 20 '13 at 14:17
  • You don't use the equal sign "=" here -- `def test(i: Int) {}` instead of `def test(i: Int) = {}` How is it possible? – Alan Coromano Jul 06 '13 at 01:49
  • http://www.informit.com/articles/article.aspx?p=1849236&seqNum=10 – some consider this syntax a bad decision, however (including Martin Odersky) – 0__ Jul 06 '13 at 07:16