6 minutes read

Programs would be not so efficient if programmers had to manually repeat parts of code again and again to perform a series of repeated actions. Think of it: even in real life, for example, when making regular log-ins or payments, the routine process is automated.

Programming languages have instruments for handling repeated routines: they are usually called loops or cycles. These cycles are conditional, and here is how it would look in pseudocode:

while condition do action

You can read it as "while the condition is met, the action is executed". Scala provides several ways of working with loops and setting conditions. In this topic, we will go over the basic ones.

Collections foreach

Let start from the very beginning: iteration over the collection elements. Early we talked about the map operation:

scala> def plusOne(i: Int): Int = i + 1
plusOne: (i: Int)Int

scala> List(1, 2, 3).map(plusOne)
res1: List[Int] = List(2, 3, 4)

Here, the function plusOne is applied to every element of the collection. This way, we already have a loop: our action produces elements as a result and the condition is true while the source collection has elements. Now, what if we wanted to iterate without producing any result, say, print the elements? For that, you can use the foreach operation:

scala> val list = List(1, 3)
list: List[Int] = List(1, 3)
scala> list.foreach(println)
1
3
scala> list.foreach(plusOne)

We passed the function println to output the elements on a new line. We could pass the plusOne function as well, but foreach can't produce any result (returns Unit).

For loop

Scala has another way of iteration over collection elements, for ??? do ???:

scala> val list = List(1, 3)
list: List[Int] = List(1, 3)
scala> for e <- list do println(e)
1
3

In the example above, we defined a loop over the list elements and used the helper value e to represent an element of the cycle. We called println function explicitly with the element. This might look a bit similar to Java cycles.

Also, for syntax gives us the ability to define more complex loops:

scala> val map = Map('a' -> 1, 'b' -> 2)
map: scala.collection.immutable.Map[Char,Int] = Map(a -> 1, b -> 2)
scala>   for
     |     key <- map.keys
     |     value <- map.values
     |   do
     |     println(s"$key => $value")
a => 1
a => 2
b => 1
b => 2

In the snippet above, we didn't iterate over the map pairs but got all the map keys and for every key got all the map values and iterated on the second loop with printing.

Yield

Earlier we commented on the similar nature of foreach and for , but we don't produce any result with them (return Unit). Do we have any relation for map and for to generate something? Yes, we could produce new collection types with help of the reserved keyword yield:

scala> def plusOne(i: Int): Int = i + 1
plusOne: (i: Int)Int
scala> for e <- List(1, 2, 3) yield plusOne(e)
res1: List[Int] = List(2, 3, 4)

Above we got exactly the same result as we did at the beginning of the topic with map. Note you don't even have to specify a function and do several inline loops:

scala> val list = List("apple", "pear")
list: List[String] = List(apple, pear, orange)
scala> for e1 <- list; e2 <- list yield s"$e1 + $e2"
res1: List[String] = List(apple + apple, apple + pear, pear + apple, pear + pear)

While loop

Finally, Scala has a while construction:

scala> var list = List('a', 'b', 'c')
list: List[Char] = List(a, b, c)
scala> while list.nonEmpty do { print(list.head); list = list.tail }
abc

In the examples, we had a condition (checking that the list is not empty) and an action (printing the plus modification for the list). It needs some kind of mutable state to stop looping: it can be a variable with a counter value:

scala> var i = 0
i: Int = 0
scala> while i < 3 do { print(i); i += 1 }
012

Note that you can use while(true) to build an infinite loop.

Conclusion

Programmers don't like to repeat themselves, so loops are fundamental. In Scala, we can iterate over predefined collection elements using foreach. With for, we can do the same with additional abilities to yield custom elements and produce inline loops. With while , we can check a mutable state as a condition and, if it's met, execute an action.

7 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo