# Conditionals, Loops and for Comprehensions — Scala

Source: https://www.geekswithgeeks.com/en/scala/c-control

> Use if, while and for comprehensions with generators, guards and yield.

## Control flow the Scala way

Scala 3 supports the new **optional-brace syntax**: `if x > 0 then ... else ...`, `while cond do ...` and `for x <- xs do ...`, with blocks marked by indentation (braces still work). The **`for` comprehension** is more than a loop. It has **generators** (`x <- xs`), **guards** (`if x > 0`) and **definitions** (`y = x * 2`), and with **`yield`** it builds a new collection: `for o <- orders if o.paid yield o.total`. Multiple generators nest like nested loops. Behind the scenes, the compiler translates `for` into calls to **`map`, `flatMap`, `withFilter` and `foreach`**, which is why for comprehensions also work with `Option`, `Either`, `Future` and effect types: a sequence of steps that may fail or run asynchronously reads like straight-line code. `while` loops exist for low-level, performance-sensitive code, but idiomatic Scala usually prefers collection operations or recursion. There is no `break` keyword; use `scala.util.boundary` and `break` from the standard library, or restructure with `find`, `takeWhile` or `exists`.

## How for comprehensions are translated

Generators become flatMap and map, and guards become withFilter.

![A for block on the left with arrows pointing to a chain of method boxes on the right labelled flatMap, withFilter and map.](assets/figures/scala/section-2-map.svg) — Figure 2.1 — for comprehensions desugar into method calls.

## for comprehensions with lists and Options

The same syntax works for collections and for values that may be missing.

```scala
case class Order(id: String, city: String, items: List[Item], paid: Boolean)
case class Item(sku: String, qty: Int, pricePaise: Int)

val orders = List(
  Order("o1", "Pune", List(Item("pen", 2, 4950), Item("ink", 1, 19900)), paid = true),
  Order("o2", "Delhi", List(Item("pad", 5, 9900)), paid = false)
)

val paidLines =
  for
    o <- orders if o.paid
    item <- o.items
    lineTotal = item.qty * item.pricePaise
  yield s"${o.id} ${item.sku}: $lineTotal"
// List(o1 pen: 9900, o1 ink: 19900)

val stock = Map("pen" -> 120, "ink" -> 0)
val prices = Map("pen" -> 4950, "ink" -> 19900)

def stockValue(sku: String): Option[Int] =
  for
    units <- stock.get(sku)            // None stops the chain
    price <- prices.get(sku)
  yield units * price

println(stockValue("pen"))             // Some(594000)
println(stockValue("pad"))             // None

var i = 0
while i < 3 do
  println(s"tick $i")
  i += 1
```

## A recipe that works in any kitchen

A for comprehension is a recipe written in steps. Whether the kitchen is a list (many results), an Option (maybe no result) or a Future (result later), each kitchen knows how to follow the same steps.

**Quiz:** What does the compiler translate a for comprehension with yield into?

- [ ] A while loop
- [ ] Java bytecode directly with no method calls
- [x] Calls to map, flatMap and withFilter
- [ ] Recursive functions only

*Answer:* Calls to map, flatMap and withFilter. Generators and guards desugar into flatMap, map and withFilter, so any type with those methods works.
