Skip to content

Scala Loop Types

While Scala supports imperative loop constructs like while and do-while, idiomatic Scala often favors functional approaches for iteration, primarily using for comprehensions and collection methods (foreach, map, filter, etc.).

Scala’s for comprehension is much more powerful than traditional for loops in other languages. It’s syntactic sugar for combinations of foreach, map, flatMap, and filter operations on collections or other types with these methods defined.

val numbers = List(1, 2, 3, 4, 5)
println("Iterating through numbers:")
for (num <- numbers) {
println(num)
}

Output:

Iterating through numbers:
1
2
3
4
5
val rangeInclusive = 1 to 5 // Inclusive range: 1, 2, 3, 4, 5
val rangeExclusive = 1 until 5 // Exclusive range: 1, 2, 3, 4
println("\nIterating through range (1 to 3):")
for (i <- 1 to 3) {
println(s"Iteration $i")
}

Output:

Iterating through range (1 to 3):
Iteration 1
Iteration 2
Iteration 3

You can add if conditions (guards) within the for comprehension to filter elements.

println("\nEven numbers:")
for (num <- numbers if num % 2 == 0) {
println(num)
}

Output:

Even numbers:
2
4

Using the yield keyword turns a for comprehension into an expression that produces a new collection based on the iterations.

val squaredNumbers = for (num <- numbers) yield num * num
println(s"\nSquared numbers: $squaredNumbers") // Output: Squared numbers: List(1, 4, 9, 16, 25)
val descriptions = for {
num <- numbers
if num > 2
} yield s"Number $num"
println(s"Descriptions: $descriptions") // Output: Descriptions: List(Number 3, Number 4, Number 5)

You can have multiple <- clauses to iterate over combinations.

val letters = List('a', 'b')
val numbersForPairing = List(1, 2)
val pairs = for {
letter <- letters
number <- numbersForPairing
} yield (letter, number)
println(s"\nPairs: $pairs") // Output: Pairs: List((a,1), (a,2), (b,1), (b,2))

Executes a block of code repeatedly as long as a condition is true. The condition is checked before each iteration.

var i = 0
println("\nWhile loop:")
while (i < 3) {
println(s"i = $i")
i += 1 // Important: ensure the condition eventually becomes false!
}

Output:

While loop:
i = 0
i = 1
i = 2

Similar to while, but the condition is checked after the loop body executes. This guarantees the body runs at least once.

var j = 5
println("\nDo-while loop:")
do {
println(s"j = $j")
j += 1
} while (j < 3) // Condition is false initially, but loop runs once

Output:

Do-while loop:
j = 5

Note: while and do-while loops are less common in idiomatic functional Scala code, as they often involve mutable state (i, j). Prefer functional alternatives like recursion or collection methods when possible.

Scala does not have break or continue keywords like Java or C++. To break out of loops early:

  • Functional Style: Refactor the loop using collection methods like find, takeWhile, exists, or recursion with base cases.
  • scala.util.control.Breaks: Provides break and breakable constructs. However, its use is generally discouraged as it relies on throwing exceptions for control flow and is less functional.
  • Return from Method: Place the loop inside a method and use return when the exit condition is met (only works if the loop is the main part of the method).

Example using functional style (finding first even number):

val data = List(1, 3, 5, 6, 7, 8)
val firstEven = data.find(_ % 2 == 0) // Returns Option[Int]
println(s"\nFirst even number: $firstEven") // Output: First even number: Some(6)