In my opinion, the for-keyword in Scala stands out among its analogues in other programming languages. This is, because it translates each so called generator in the brackets following the for-keyword into a function call and doesn’t technically loop through some body. This being said, we are going to discuss first the, in my opinion, misnamed for-loops.

For-Loops

Let’s consider the simple expression

for( x <- list) println(x)

this will be translated by the Scala compiler to

list foreach (x => println)

The x <- list part in the above example is called a generator. It can look more involved and for these details I’m referring to the Further Reading section.

Now, if the list object in this example is not of type ListA, as the name is suggesting, but of some other type which doesn’t have a foreach function the Scala compiler will throw an error:

for( x <- new Test(3)) println(x)
->error: value foreach is not a member of Test

So far so good: We might have seen a pretty elegant way to reduce for-loops to something more primary by the Scala compiler, but in the end it does nothing more than your standard Python or Java loop.

For-Expressions

This is changing, however, with the so called for-expressions which use the yield-keyword. A simple example of a for-expression looks like this:

val list = List(1, 2, 3)
for( x <- list) yield 2*x

If you type this in your scala interpreter the output will be

List[Int] = List(2, 4, 6)

It returned a List! Why is that?

As with for-loops, this for-expression is syntactic sugar for a map applied to the list-object. Scala translates the above expression to

list.map(x => 2*x)

This is in fact equivalent to the above for-expression!

But wait: what if put two of these generators into the brackets of our for-expression?

val list = List(1, 2, 3)
val list2 = List(3, 2, 1)
for(x <- list; y <- list2) yield x-y

Here the result is:

List[Int] = List(-2, -1, 0, -1, 0, 1, 0, 1, 2)

It turns out, this is translated to a flatMap followed by a map:

list.flatMap(x => list2.map(y => x-y))

This doesn’t just work for Scala collections but also for your own data types. And even better: if you only define, say, a map function in your own data type, you will still be able to use for-expressions with only one generator on your data type. (Why? - because Scala does the type checking only after translating the for-loops and for-expressions.)

Further Reading

How does this work in general you may ask? Since there are much more general for-expressions than those I have covered so far, I will stop here and refer those who are interested to the following links.