Marcus Downing
Marcus Downing

Reputation: 10141

Scala's for-comprehensions: vital feature or syntactic sugar?

When I first started looking at Scala, I liked the look of for-comprehensions. They seemed to be a bit like the foreach loops I was used to from Java 5, but with functional restrictions and a lot of sweet syntactic niceness.

But as I've absorbed the Scala style, I find that every time I could use a for-comprension I'm using map, flatMap, filter, reduce and foreach instead. The intention of the code seems clearer to me that way, with fewer potential hidden surprises, and they're usually shorter code too.

As far as I'm aware, for-comprehensions are always compiled down into these methods anyway, so I'm wondering: what are they actually for? Am I missing some functional revalation (it wouldn't be the first time)? Do for-comprehensions do something the other features can't, or would at least be much clumsier at? Do they shine under a particular use case? Is it really just a matter of personal taste?

Upvotes: 19

Views: 11506

Answers (5)

thSoft
thSoft

Reputation: 22660

In some cases, for comprehensions can express intent better, so when they do, use them.

Also note that with for comprehensions, you get pattern matching for free. For example, iterating over a Map is much simpler with for comprehension:

for ((key, value) <- map) println (key + "-->" + value)

than with foreach:

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

Upvotes: 5

Walter Chang
Walter Chang

Reputation: 11596

Another great use of for-comprehension is for internal DSL. ScalaQL is a great example of this. It can turn this

val underAge = for { 
  p <- Person 
  c <- Company 
  if p.company is c 
  if p.age < 14 
} yield p 

into this

SELECT p.* FROM people p JOIN companies c ON p.company_id = c.id WHERE p.age < 14 

and a whole lot more.

Upvotes: 12

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297195

Please refer to this question. The short answer is that for-comprehensions can be more readable. In particular, if you have many nested generators, the actual scope of what you are doing becomes more clear, and you don't need huge indents.

Upvotes: 15

Synesso
Synesso

Reputation: 38978

You are right. The for-comprehension is syntactic sugar. I believe the underlying methods are more succinct and easier to read, once you are used to them.

Compare the following equivalent statements:

1. for (i <- 1 to 100; if (i % 3 == 0)) yield Math.pow(i, 2)
2. (1 to 100).filter(_ % 3 == 0).map(Math.pow(_, 2))

In my opinion, the addition of the semicolon in #1 distracts from the sense that this is a single chained statement. There is also a sense that i is a var (is it 1, or is it 99, or something inbetween?) which detracts from an otherwise functional style.

Option 2 is more evidently a chain of method calls on objects. Each link in the chain clearly stating its responsibility. There are no intermediate variables.

Perhaps for comprehensions are included as a convenience for developers transitioning from Java. Regardless, which is chosen is a matter of style and preference.

Upvotes: 3

Erik Engbrecht
Erik Engbrecht

Reputation: 3164

for-comprehensions are syntactic sugar, but that doesn't mean they aren't vital. They are usually more concise than their expanded form, which is nice, but perhaps more importantly they help programmers from imperative languages use functional constructs.

When I first started with Scala I used for-comprehensions a lot, because they were familiar. Then I almost stopped completely, because I felt like using the underlying methods was more explicit and therefore clearer. Now I'm back to using for-comprehensions because I think they better express the intent of what I'm doing rather than the means of doing it.

Upvotes: 10

Related Questions