Imperative Loops in Scala
Scala supports the familiar while and do-while loops inherited from imperative languages, but they are used sparingly in idiomatic Scala because they rely on mutable state and produce Unit, giving them no return value to compose with the rest of an expression-oriented language. A while (condition) { body } loop repeatedly executes its body only while the condition holds, checked before each iteration, whereas do { body } while (condition) guarantees the body runs at least once before the condition is checked - both remain useful for tight, performance-sensitive loops or when interfacing with mutable, stateful APIs.
Cricket analogy: A bowler running through a fixed pre-delivery routine (mark the run-up, check the field, bowl) every single ball regardless of the match situation is like a do-while loop - the routine runs at least once before any condition about the next ball is even considered.
for Loops and Ranges
The most common way to iterate a fixed number of times is for (i <- 1 to 10), which iterates over a Range object built by the to (inclusive) or until (exclusive) methods on Int; by default a bare for loop without yield is executed purely for its side effects, such as printing, and itself evaluates to Unit. Ranges can also specify a step, as in 1 to 10 by 2, and iterating in reverse is done with 10 to 1 by -1, since a naive ascending range with a negative step produces an empty sequence.
Cricket analogy: An over consists of exactly 1 to 6 deliveries - an inclusive range where both endpoints count, just as Scala's to method includes both boundary values, unlike until which excludes the upper bound.
for (i <- 1 to 5) println(s"Iteration $i")
for (i <- 10 to 1 by -3) println(i) // 10, 7, 4, 1for Comprehensions with yield
Adding yield transforms a for loop from a side-effecting statement into a for comprehension that produces a new collection: for (x <- List(1, 2, 3)) yield x * 2 returns List(2, 4, 6). Under the hood, this is pure syntactic sugar that the compiler desugars into calls to map, flatMap, and withFilter on whatever collection type is being iterated - a single generator with yield becomes map, multiple generators become nested flatMap calls, and any if guard becomes a withFilter call, which is why any type that implements those methods (like Option or Future) can be used in a for comprehension, not just collections.
Cricket analogy: A run-chase calculator that takes each ball faced and 'yields' a running required-run-rate value for every delivery, rather than just printing scores, is like Scala's for-yield transforming each element into a new value collected into a result.
val pairs = for {
x <- List(1, 2, 3)
y <- List("a", "b")
} yield (x, y)
// List((1,a), (1,b), (2,a), (2,b), (3,a), (3,b))Guards and Nested Generators
Multiple generators inside a single for block, separated by newlines or semicolons within braces, produce a cross-product-style nested iteration, and adding an if guard such as if x % 2 == 0 filters out combinations before the yield is evaluated, exactly as if .withFilter(x => x % 2 == 0) had been called explicitly. Because each generator can also introduce an intermediate val binding (e.g., total = x + y), for comprehensions become a concise way to express filtered, multi-step transformations that would otherwise require deeply nested flatMap/map/filter chains.
Cricket analogy: A fixture scheduler generating every possible team pairing across two divisions, then filtering out pairs where both teams are from the same city, is like Scala's nested for-generators with an if guard acting as withFilter to drop unwanted combinations.
For comprehensions work with any type that defines map and flatMap (and optionally withFilter) - this includes Option, Try, and Future, which is why you'll often see for { a <- optionA; b <- optionB } yield a + b used to chain optional or asynchronous computations cleanly.
A for loop without yield returns Unit and exists purely for its side effects - using it when you actually meant to build a new collection is a common beginner mistake; forgetting yield silently discards all the values instead of raising an error.
- while and do-while are imperative loops that mutate state and evaluate to Unit.
- for loops without yield run only for side effects and also evaluate to Unit.
- to includes the upper bound; until excludes it; by sets a custom step, including negative for descending ranges.
- Adding yield turns a for loop into a for comprehension that builds a new collection.
- For comprehensions desugar to map, flatMap, and withFilter, so any type implementing those (Option, Future) can be used.
- Guards (if) inside a for comprehension filter elements before yield is applied, equivalent to calling withFilter.
- Multiple generators create nested iteration equivalent to nested flatMap/map calls.
Practice what you learned
1. What does a while loop evaluate to in Scala?
2. What is the difference between `1 to 10` and `1 until 10`?
3. What does adding yield to a for loop do?
4. For comprehensions with a single generator and yield desugar into a call to which method?
5. What happens if you write a for loop with multiple generators but no if guard to filter results?
Was this page helpful?
You May Also Like
Functions in Scala
Learn how to define, call, and structure functions in Scala using def, including default parameters, named arguments, and multiple parameter lists.
Higher-Order Functions
Learn how Scala functions that accept or return other functions enable powerful, reusable abstractions like map, filter, fold, and currying.
Conditionals and Match Expressions
Understand how Scala treats if-else and match as expressions that return values, including pattern matching on case classes and sealed traits.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics