for expressions versus foreach in Scala

ScalaLoopsForeach

Scala Problem Overview


I'm working my way through Programming in Scala, and though I'm tempted to look at things from the perspective of Python, I don't want to program "Python in Scala."

I'm not quite sure what to do as far as control flow goes: in Python, we use for x in some_iterable to death, and we love it. A very similar construct exists in Scala which Odersky calls a for expression, probably to distinguish it from the Java for loop. Also, Scala has a foreach attribute (I guess it would be an attribute, I don't know enough about Scala to name it correctly) for iterable data types. It doesn't seem like I can use foreach to do much more than call one function for each item in the container, though.

This leaves me with a few questions. First, are for expressions important/heavily used constructs in Scala like they are in Python, and second, when should I use foreach instead of a for expression (other than the obvious case of calling a function on each item of a container)?

I hope I'm not being terribly ambiguous or overbroad, but I'm just trying to grok some of the design/language fundamentals in Scala (which seems very cool so far).

Scala Solutions


Solution 1 - Scala

python uses for in list comprehensions and generator expressions. Those are very similar to the scala for expression:

this is python

>>> letters = ['a', 'b', 'c', 'd']
>>> ints = [0, 1, 2, 3]
>>> [l + str(i) for l in letters for i in ints if i % 2 == 0]
['a0', 'a2', 'b0', 'b2', 'c0', 'c2', 'd0', 'd2']

this is scala

scala> val letters = List('a', 'b', 'c', 'd')
scala> val ints = List(0, 1, 2, 3)
scala> for (l <- letters; i <- ints if i % 2 == 0) yield l.toString + i
res0: List[java.lang.String] = List(a0, a2, b0, b2, c0, c2, d0, d2)

Each construct can take a number of generators/iterators, apply filters expressions and yield a combined expression. In python the (expr for v1 in gen1 if expr1 for v2 in gen2 if expr2) is roughly equivalent to:

for v1 in gen1:
  if expr1:
    for v2 in gen2:
      if expr2:
        yield expr

In scala for (v1 <- gen1 if expr1; v2 <- gen2 if expr2) yield expr is roughly equivalent to:

gen1.withFilter(expr1).flatMap(v1 => gen2.withFilter(expr2).map(v2 => expr))

If you love the python for x in xs syntax, you'll likely love the scala for expression.

Scala has some additional syntax and translation twists. Syntax wise for can be used with braces so that you can put statements on separate lines. You can also perform value assignments.

val res = for {
    i <- 1 to 20; i2 = i*i
    j <- 1 to 20; j2 = j*j
    k <- 1 to 20; k2 = k*k
    if i2 + j2 == k2
  } yield (i, j, k)

Also v1 <- gen1 really performs a match case v1 => gen1. If there is no match those elements are ignored from the iteration.

scala> val list = List(Some(1), None, Some(2))
scala> for (Some(i) <- list) yield i
res2: List[Int] = List(1, 2)

I think for has an important place in the language. I can tell from the fact there is a whole chapter (23) about it in the book you're reading!

Solution 2 - Scala

Yes, Scala for comprehensions (as they are commonly known) are used a lot, but they are really just syntactic sugar for a particular combination of methods, and many prefer to call these methods directly instead of using the syntactic sugar.

To better understand Scala for comprehensions, please refer to this question. In particular, you'll see that for (x <- xs) f(x) is the same thing as xs.foreach(x => f(x)).

Now, you mention that you don't seem much use with foreach method, but I'll point out that almost all of the methods of Scala collections are (or can be) implemented with just foreach. See the documentation for Traversable -- all of its methods can be implemented with only foreach.

Note that Scala's yield bears no resemblance to Python's yield -- you can look up that question too.

Solution 3 - Scala

With its support for nested iteration, filters, and transformation, I'd say Scala's for is one of the strong points of the language and very central. I tend to favor it over using foreach, map and filter.

Solution 4 - Scala

The foreach is a functional style while the for is an imperative style. If you've ever done any lisp or scheme, you're already familiar with functional programming. If you haven't then it might be a bit confusing at first. The first thing I would do is read up on the closure syntax which are anonymous functions you pass into things like foreach. Once you understand that it will all make more sense.

Solution 5 - Scala

Your questions are largely answered by the following:

Scala's For Comprehensions

Scala Yield

To summaraize: It's largely stylistic. Personally, I favor the functional methodology, but prefer the succinctness of comprehensions when dealing with nested loops.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRafe KettlerView Question on Stackoverflow
Solution 1 - ScalahuynhjlView Answer on Stackoverflow
Solution 2 - ScalaDaniel C. SobralView Answer on Stackoverflow
Solution 3 - ScalaFabian SteegView Answer on Stackoverflow
Solution 4 - ScalaJOTNView Answer on Stackoverflow
Solution 5 - ScalaNorthoverView Answer on Stackoverflow