Looping in Scala

As I’ve noted before, Scala is so functional that every instruction has a value, as it happens in math. Scala is also functional in avoiding the standard three-elements-loop construct:

/* C/C++/Java classic for loop */
for (initial condition; comparative condition; incremental instruction) { ... }

This was considered so wrong by Scala designers that they purposely avoided including this construct. Since Scala has while loops, is always possible to replace this missing construct with a classic:

var variable = <initial state>
while (variable != <end state>) {
    ... do something ...
    variable += 1
}

This is however considered bad programming in Scala. Every book would suggest another form on this task:

for (i <- <initial> to <final>) { ... }

The i variable will be iterated over all the values between and . The to token between the two endpoints is not a language keyword. It is instead a method of the Int class. It returns a list of values starting from the initial value and ending at the final value, both included. To be precise, the to mehod does not come from the Int class, but from the RichInt class which the Int class can be automatically converted into, because of an implicit declaration. I’ll cover Scala implicits in future posts for sure because so much of the power (or magic!) of Scala happens because of its impicits.

Back to the loops, there’s much more to say about. First of all, in Scala you can declare the equivalent of nested loops in one single for expression:

scala> for (i <- 1 to 3; j <- 5 to 6) { println ("i: " + i + " // j: " + j) }
i: 1 // j: 5
i: 1 // j: 6
i: 2 // j: 5
i: 2 // j: 6
i: 3 // j: 5
i: 3 // j: 6

This is without any doubt a typesaving feature. What’s best, you can even use one of the iterating variables as start or endpoint of inner iterations:

scala> for (i <- 1 to 3; j <- i to 6) { println ("i: " + i + " // j: " + j) }
i: 1 // j: 1
i: 1 // j: 2
i: 1 // j: 3
i: 1 // j: 4
i: 1 // j: 5
i: 1 // j: 6
i: 2 // j: 2
i: 2 // j: 3
i: 2 // j: 4
i: 2 // j: 5
i: 2 // j: 6
i: 3 // j: 3
i: 3 // j: 4
i: 3 // j: 5
i: 3 // j: 6

To add even more, a for loop has a value which can be assigned to a variable:

scala> val l = for (i <- 1 to 5) yield i
l: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)

Here l is a collection: a Vector containing the values from 1 to 5.

for loops can also add guards that filter out values you don’t want to iterate over:

scala> for (i <- 1 to 10 if i % 2 == 0) { println ("i: " + i ) }
i: 2
i: 4
i: 6
i: 8
i: 10

Here I’ve used the modulo division to filter out odd numbers. Of course I could combine the last two concepts to get a Vector with all the first even numbers under 10:

scala> val even10 = for (i <- 1 to 10 if i % 2 == 0) yield i
even10: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

Another way to have this result is using the other to method which takes an additional step parameter:

scala> for (i <- 2 to (10, 2)) yield i
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

You may find this syntax confusing (at least this was true for me). Why are the parenthesis wrapping 10 and 2? Wouldn’t be clearer:

for (i <- (2 to 10, 2)) yield i // wrong!

or something similar? Well, if you’re wondering this, you’re not thinking as a functional programmer. You are not remembering that to is a method. Whenever a method takes one single parameters, the parenthesis can be omitted. But when two or more parameters have to be passed, the parenthesis must be explicited. So: to(10, 2). The previous for loop could also be written in the more explicit, but less readable form:

for (i <- 2.to(10, 2)) yield i

This is just a taste of Scala compact and expressive syntax. Further posts will follow.