What is the formal difference between passing arguments to functions in parentheses ()
and in braces {}
?
The feeling I got from the Programming in Scala book is that Scala's pretty flexible and I should use the one I like best, but I find that some cases compile while others don't.
For instance (just meant as an example; I would appreciate any response that discusses the general case, not this particular example only):
val tupleList = List[(String, String)]()
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 )
=> error: illegal start of simple expression
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }
=> fine.
I tried once to write about this, but I gave up in the end, as the rules are somewhat diffuse. Basically, you’ll have to get the hang of it.
Perhaps it is best to concentrate on where curly braces and parenthesis can be use interchangeably: when passing parameters to method calls. You may replace parenthesis with curly braces if, and only if, the method expects a single parameter. For example:
However, there’s more you need to know to better grasp these rules.
Increased compile checking with parens
The authors of Spray recommend round parens because they give increased compile checking. This is especially important for DSLs like Spray. By using parens you are telling the compiler that it should only be given a single line; therefore if you accidentally give it two or more, it will complain. Now this isn’t the case with curly braces – if for example you forget an operator somewhere, then your code will compile, and you get unexpected results and potentially a very hard bug to find. Below is contrived (since the expressions are pure and will at least give a warning), but makes the point:
The first compiles, the second gives
error: ')' expected but integer literal found
. The author wanted to write1 + 2 + 3
.One could argue it’s similar for multi-parameter methods with default arguments; it’s impossible to accidentally forget a comma to separate parameters when using parens.
Verbosity
An important often overlooked note about verbosity. Using curly braces inevitably leads to verbose code since the Scala style guide clearly states that closing curly braces must be on their own line:
Many auto-reformatters, like in IntelliJ, will automatically perform this reformatting for you. So try to stick to using round parens when you can.
Infix Notation
When using infix notation, like
List(1,2,3) indexOf (2)
you can omit parenthesis if there is only one parameter and write it asList(1, 2, 3) indexOf 2
. This is not the case of dot-notation.Note also that when you have a single parameter that is a multi-token expression, like
x + 2
ora => a % 2 == 0
, you have to use parenthesis to indicate the boundaries of the expression.Tuples
Because you can omit parenthesis sometimes, sometimes a tuple needs extra parenthesis like in
((1, 2))
, and sometimes the outer parenthesis can be omitted, like in(1, 2)
. This may cause confusion.Function/Partial Function literals with
case
Scala has a syntax for function and partial function literals. It looks like this:
The only other places where you can use
case
statements are with thematch
andcatch
keywords:You cannot use
case
statements in any other context. So, if you want to usecase
, you need curly braces. In case you are wondering what makes the distinction between a function and partial function literal, the answer is: context. If Scala expects a function, a function you get. If it expects a partial function, you get a partial function. If both are expected, it gives an error about ambiguity.Expressions and Blocks
Parenthesis can be used to make subexpressions. Curly braces can be used to make blocks of code (this is not a function literal, so beware of trying to use it like one). A block of code consists of multiple statements, each of which can be an import statement, a declaration or an expression. It goes like this:
So, if you need declarations, multiple statements, an
import
or anything like that, you need curly braces. And because an expression is a statement, parenthesis may appear inside curly braces. But the interesting thing is that blocks of code are also expressions, so you can use them anywhere inside an expression:So, since expressions are statements, and blocks of codes are expressions, everything below is valid:
Where they are not interchangeable
Basically, you can’t replace
{}
with()
or vice versa anywhere else. For example:This is not a method call, so you can’t write it in any other way. Well, you can put curly braces inside the parenthesis for the
condition
, as well as use parenthesis inside the curly braces for the block of code:So, I hope this helps.
With braces, you got semicolon induced for you and parentheses not. Consider
takeWhile
function, since it expects partial function, only{case xxx => ??? }
is valid definition instead of parentheses around case expression.Because you are using
case
, you are defining a partial function and partial functions require curly braces.There are a couple of different rules and inferences going on here: first of all, Scala infers the braces when a parameter is a function, e.g. in
list.map(_ * 2)
the braces are inferred, it's just a shorter form oflist.map({_ * 2})
. Secondly, Scala allows you to skip the parentheses on the last parameter list, if that parameter list has one parameter and it is a function, solist.foldLeft(0)(_ + _)
can be written aslist.foldLeft(0) { _ + _ }
(orlist.foldLeft(0)({_ + _})
if you want to be extra explicit).However, if you add
case
you get, as others have mentioned, a partial function instead of a function, and Scala will not infer the braces for partial functions, solist.map(case x => x * 2)
won't work, but bothlist.map({case x => 2 * 2})
andlist.map { case x => x * 2 }
will.I think it is worth explaining their usage in function calls and why various things happen. As someone already said curly braces define a block of code, which is also an expression so can be put where expression is expected and it will be evaluated. When evaluated, its statements are executed and last's statement value is the result of whole block evaluation (somewhat like in Ruby).
Having that we can do things like:
Last example is just a function call with three parameters, of which each is evaluated first.
Now to see how it works with function calls let's define simple function that take another function as a parameter.
To call it, we need to pass function that takes one param of type Int, so we can use function literal and pass it to foo:
Now as said before we can use block of code in place of an expression so let's use it
What happens here is that code inside {} is evaluated, and the function value is returned as a value of the block evaluation, this value is then passed to foo. This is semantically the same as previous call.
But we can add something more:
Now our code block contains two statements, and because it is evaluated before foo is executed, what happens is that first "Hey" is printed, then our function is passed to foo, "Entering foo" is printed and lastly "4" is printed.
This looks a bit ugly though and Scala lets us to skip the parenthesis in this case, so we can write:
or
That looks much nicer and is equivalent to the former ones. Here still block of code is evaluated first and the result of evaluation (which is x => println(x)) is passed as an argument to foo.
I don't think there is anything particular or complex about curly braces in Scala. To master the seeming-complex usage of them in Scala, just keep a couple of simple things in mind:
Let's explain a couple of examples per the above three rules: