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 List[A], 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.