Asked  7 Months ago    Answers:  5   Viewed   42 times

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.

 Answers

39

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 used 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:

List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter

List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter

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:

method {
  1 +
  2
  3
}

method(
  1 +
  2
  3
)

The first compiles, the second gives error: ')' expected but integer literal found. The author wanted to write 1 + 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:

… the closing brace is on its own line immediately following the last line of the function.

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 as List(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 or a => 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:

{
    case pattern if guard => statements
    case pattern => statements
}

The only other places where you can use case statements are with the match and catch keywords:

object match {
    case pattern if guard => statements
    case pattern => statements
}
try {
    block
} catch {
    case pattern if guard => statements
    case pattern => statements
} finally {
    block
}

You cannot use case statements in any other context. So, if you want to use case, 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:

{
    import stuff._
    statement ; // ; optional at the end of the line
    statement ; statement // not optional here
    var x = 0 // declaration
    while (x < 10) { x += 1 } // stuff
    (x % 5) + 1 // expression
}

( expression )

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:

( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1

So, since expressions are statements, and blocks of codes are expressions, everything below is valid:

1       // literal
(1)     // expression
{1}     // block of code
({1})   // expression with a block of code
{(1)}   // block of code with an expression
({(1)}) // you get the drift...

Where they are not interchangeable

Basically, you can’t replace {} with () or vice versa anywhere else. For example:

while (x < 10) { x += 1 }

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:

while ({x < 10}) { (x += 1) }

So, I hope this helps.

Tuesday, June 1, 2021
 
EzzDev
answered 7 Months ago
90

You can find here a preview of new feature in Scala2.8 (April 2009), completed with recent this article (June 2009)

  • Named and Default Arguments
  • Nested Annotations
  • Package Objects
  • @specialized
  • Improved Collections (some rewrite might be needed here)
  • REPL will have command completion (more on that and other tricks in this article)
  • New Control Abstractions (continuation or break)
  • Enhancements (Swing wrapper, performances, ...)

"Rewriting code" is not an obligation (except for using some of the improved Collections), but some features like continuation (Wikipedia: an abstract representation of the control state, or the "rest of computation" or "rest of code to be executed") can give you some new ideas. A good introduction is found here, written by Daniel (who has also posted a much more detailed and specific answer in this thread).

Note: Scala on Netbeans seems to work with some 2.8 nightly-build (vs. the official page for 2.7.x)

Saturday, July 10, 2021
 
RompelStompel
answered 5 Months ago
70

There are a couple differences, but they're not big:

  1. .create is equivalent to .new followed by .save. It's just more succinct.
  2. .create! is equivalent to .new followed by .save! (throws an error if saving fails). It's also just a wee bit shorter
  3. I think .build is mostly an alias for .new. It works one way in Rails 3 and another way in Rails < 3.x

The most important part, however, is that these methods can be called through an association (has_many, etc.) to automatically link the two models.

Tuesday, July 27, 2021
 
wavyGravy
answered 5 Months ago
36

Its called as "var args" (variable arguments).

def concat(strs: String*): String = strs.foldLeft("")(_ ++ _)

Scala REPL

scala> def concat(strs: String*): String = strs.foldLeft("")(_ ++ _)
concat: (strs: String*)String

scala> concat()
res6: String = ""

scala> concat("foo")
res7: String = foo

scala> concat("foo", " ", "bar")
res8: String = foo bar
Saturday, August 14, 2021
 
user729076
answered 4 Months ago
74

Unfortunately it is not possible and I see no way to simplify your first example.

The case statement has to be followed by a Pattern. The Scala Language Specification shows the BNF of patterns in section 8.1. The grammar of patterns is quite powerful, but is really just a pattern, no method calls or constructors are allowed there.

Wednesday, October 13, 2021
 
Landys
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share