Expressions and control structures

Scala · Essentials · 10 min

Thinking in expressions instead of statements is what makes Scala code concise.

In Scala nearly everything is an expression with a value. if returns a value, so there's no ternary operator: val sign = if x < 0 then -1 else 1. A block { ... } (or an indented block) evaluates to its last expression. An if without else yields () when the condition is false, so its value is rarely useful.

Loops:

  • while cond do body is the imperative loop; it returns Unit.
  • for i <- 1 to 5 do println(i) iterates over a range or collection. 1 to 5 includes 5, 1 until 5 excludes it, and by sets a step.
  • Several generators and guards can be combined: for i <- 1 to 3; j <- 1 to 3 if i != j do ....
  • for x <- xs yield f(x) builds a new collection: a for expression. Its result type follows the input collection.

match is the other key control structure (covered in pattern matching): x match { case 1 => "one"; case _ => "many" }.

There is no break or continue keyword. Usually a collection method (find, takeWhile, exists) expresses the intent better; scala.util.boundary with break exists for the rare cases you need an early exit.

try/catch/finally is an expression too, and return is rarely used: the last expression of a method is its result.

Example

val x = -7
val sign = if x < 0 then "negative" else "non-negative"
println(sign)                               // negative

val total =
  val a = 10
  val b = 32
  a + b                                     // value of the block
println(total)                              // 42

var n = 1
while n < 100 do n *= 3
println(n)                                  // 243

for i <- 1 to 3; j <- 1 to 3 if i < j do
  print(s"($i,$j) ")                        // (1,2) (1,3) (2,3)
println()

val squares = for k <- 1 until 5 yield k * k
println(squares)                            // Vector(1, 4, 9, 16)
println((10 to 1 by -3).toList)             // List(10, 7, 4, 1)

Remember

  • if, blocks, match, try and for ... yield all return values
  • 1 to n includes n, 1 until n excludes it
  • for ... do loops for effects, for ... yield builds collections

Watch out for

  • Writing an if without else and expecting a useful value: the missing branch is ().

Check yourself

  1. What is the type of if (cond) 42 with no else branch?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.scala-lang.org/scala3/book/control-structures.html