Scala Control Flow: if/else, match, while, and for Loops

TT
TopicTrick

Scala's control flow structures are familiar to any programmer but with an important twist: most of them are expressions — they return values. This functional characteristic allows you to eliminate mutable variables and write cleaner, more composable code.

if/else as an Expression

In Scala, if/else is an expression that returns a value — not just a statement that controls execution:

scala
val age = 25
val status = if age >= 18 then "adult" else "minor"
// status: String = "adult"

Since if/else returns a value, you can use it anywhere an expression is expected — in variable assignments, function arguments, and interpolated strings:

scala
val message = s"You are ${if age >= 18 then "an adult" else "a minor"}"

def absoluteValue(n: Int): Int =
  if n >= 0 then n else -n

Scala 3 uses then for clarity (Scala 2 used parentheses: if (age >= 18)).

When both branches return different types, Scala infers the least upper bound:

scala
val result = if true then 42 else "hello"
// result: Int | String = 42  (Scala 3 union type)
// or: result: Any = 42       (Scala 2)

The match Expression

match is Scala's powerful pattern matching construct — far more expressive than Java's switch:

scala
val day = "Monday"
val kind = day match
  case "Saturday" | "Sunday" => "weekend"
  case "Monday"              => "start of week"
  case _                     => "weekday"

match is also an expression returning a value. The _ wildcard is the default case.

Matching on types:

scala
def describe(x: Any): String = x match
  case n: Int    => s"Integer: $n"
  case s: String => s"String of length ${s.length}"
  case true      => "Boolean true"
  case _         => "something else"

Matching with guards:

scala
val n = 15
val category = n match
  case x if x < 0  => "negative"
  case 0            => "zero"
  case x if x < 10 => "small"
  case _            => "large"

while Loops

Scala has while for imperative iteration, though it is used sparingly in idiomatic functional code:

scala
var i = 0
while i < 5 do
  println(s"i = $i")
  i += 1

do/while also exists:

scala
var x = 0
do
  println(x)
  x += 1
while x < 3

In functional Scala, while is replaced by recursive functions or collection operations. However, while remains valid for performance-critical inner loops.

for Loops and for Comprehensions

Scala's for loop is a clean syntax over collection iteration:

scala
for i <- 1 to 5 do
  println(i)
// 1 2 3 4 5

for item <- List("a", "b", "c") do
  println(item)

Multiple generators (nested loops):

scala
for
  x <- 1 to 3
  y <- 1 to 3
do
  println(s"($x, $y)")

Guards (filter with if):

scala
for
  x <- 1 to 10
  if x % 2 == 0
do
  println(x)
// 2 4 6 8 10

yield — producing a collection:

scala
val squares = for x <- 1 to 5 yield x * x
// squares: IndexedSeq[Int] = Vector(1, 4, 9, 16, 25)

With yield, the for becomes a for comprehension — it builds and returns a new collection rather than just executing side effects. This is the functional heart of Scala's for syntax.

Ranges

Scala has concise range syntax:

scala
1 to 5        // inclusive: 1, 2, 3, 4, 5
1 until 5     // exclusive: 1, 2, 3, 4
1 to 10 by 2  // step: 1, 3, 5, 7, 9

Frequently Asked Questions

Q: When should I use match versus if/else? Use match when you are branching on the value or type of a single expression, especially when there are three or more cases. match with sealed trait hierarchies ensures exhaustiveness (the compiler warns if you miss a case). Use if/else for simple binary conditions or when the condition involves multiple independent variables.

Q: What does case _ => mean in a match expression? The underscore _ is the wildcard pattern — it matches any value. case _ => is the catch-all default case, equivalent to Java's default:. Without a wildcard, if no case matches, Scala throws a MatchError at runtime. Using a wildcard prevents this for non-exhaustive matches.

Q: Can a for loop return a value without yield? A for loop without yield returns Unit — it is purely for side effects. Adding yield transforms it into a for comprehension that produces a collection. You cannot use the result of a for without yield as a value.


Part of the Scala Mastery Course — Module 4 of 22.