Scala has only a handful of built-in control structures. The only control struc- tures are if, while, for, try, match, and function calls.

One thing you will notice is that almost all of Scala’s control structures result in some value. This is the approach taken by functional languages, where programs are viewed as computing a value, thus the components of a program should also compute values.

If expressions

var filename = "default.txt"
if (!args.isEmpty)
  filename = args(0)

Above code can be written more nicely without using any vars:

val filename =
  if (!args.isEmpty) args(0)
  else "default.txt"

Scala’s idiom for conditional initialization

  • This code is slightly shorter, but its real advantage is that it uses a val instead of a var.
  • Using a val is the functional style, and it helps you in much the same way as a final variable in Java. It tells readers of the code that the variable will never change, saving them from scanning all code in the variable’s scope to see if it ever changes.
  • A second advantage to using a val instead of a var is that it better sup- ports equational reasoning.

Look for opportunities to use vals. They can make your code both easier to read and easier to refactor.

While loops

def gcdLoop(x: Long, y: Long): Long = {
  var a = x
  var b = y
  while (a != 0) {
    val temp = a a = b % a
    b = temp

Calculating greatest common divisor with a while loop

var line = ""
do {
  line = readLine()
  println("Read: " + line)
} while (line != "")

Reading from the standard input with do-while

The while and do-while constructs are called “loops,” not expressions, because they don’t result in an interesting value.

  • The type of the result is Unit.
  • It turns out that a value (and in fact, only one value) exists whose type is Unit.
  • It is called the unit value and is written ().
  • The existence of () is how Scala’s Unit differs from Java’s void.

One other construct that results in the unit value, which is relevant here, is reassignment to vars. For example, were you to attempt to read lines in Scala using the following while loop idiom from Java (and C and C++), you’ll run into trouble:

var line = ""
while ((line = readLine()) != "") // This doesn't work!
  println("Read: " + line)
  • When you compile this code, Scala will give you a warning that comparing values of type Unit and String using != will always yield true.
  • Whereas in Java, assignment results in the value assigned (in this case a line from the standard input), in Scala assignment always results in the unit value, ().
  • Thus, the value of the assignment “line = readLine()” will always be () and never be "".
  • As a result, this while loop’s condition will never be false, and the loop will, therefore, never terminate.

while loop results in no value

In general, we recommend you challenge while loops in your code in the same way you challenge vars.

For expressions

Scala’s for expression is a Swiss army knife of iteration.

val filesHere = (new".")).listFiles
for (file <- filesHere)

Listing files in a directory with a for expression

  • With the “file <- filesHere” syntax, which is called a generator, we iterate through the elements of filesHere.
  • In each iteration, a new val named file is initialized with an element value.
  • The compiler infers the type of file to be File, because filesHere is an Array[File].
  • Because File’s toString method yields the name of the file or directory, the names of all the files and directories in the current directory will be printed.
  • The for expression syntax works for any kind of collection, not just arrays.

One convenient special case is the Range type. You can create Ranges using syntax like “1 to 5” and can iterate through them with a for. Here is a simple example:

for (i <- 1 to 4)
  println("Interation " + i)
for (i <- 1 until 4) // not include the upper bound of the range
  println("Interation " + i)
val filesHere = (new".")).listFiles
for (file <- filesHere if file.getName.endsWith(".scala"))

Finding .scala files using a for with a filter

You can include more filters if you want. Just keep adding if clauses.

for (
  file <- filesHere
  if file.isFile
  if file.getName.endsWith(".scala")
) println(file)

Using multiple filters in a for expression

def fileLines(file: =
def grep(pattern: String) =
  for (file <- filesHere
       if file.getName.endsWith(".scala");
       line <- fileLines(file)
       if line.trim.matches(pattern)) println(file + ": " + line.trim)

Using multiple generators in a for expression

  • you can use curly braces instead of parentheses to surround the generators and filters
  • One advantage to using curly braces is that you can leave off some of the semicolons that are needed when you use parentheses because the Scala compiler will not infer semi- colons while inside parentheses.

Note that the previous code repeats the expression line.trim. This is a non-trivial computation, so you might want to only compute it once. You can do this by binding the result to a new variable using an equals sign (=). The bound variable is introduced and used just like a val, only with the val keyword left out.

def grep(pattern: String) =
  for {
    file <- filesHere
    if file.getName.endsWith(".scala")
    line <- fileLines(file)
    trimmed = line.trim
    if trimmed.matches(pattern)
  } println(file + ": " + trimmed)

Mid-stream assignment in a for expression

While all of the examples so far have operated on the iterated values and then forgotten them, you can also generate a value to remember for each iteration.
To do so, you prefix the body of the for expression by the keyword yield.

def scalaFiles =
  for {
    file <- filesHere
    if file.getName.endsWith(".scala")
  } yield file
  • Each time the body of the for expression executes, it produces one value, in this case simply file.
  • When the for expression completes, the result will include all of the yielded values contained in a single collection.
  • The type of the resulting collection is based on the kind of collections processed in the iteration clauses.
  • In this case the result is an Array[File], because filesHere is an array and the type of the yielded expression is File.

The syntax of a for-yield expression is like this:

for clauses yield body
val forLineLengths =
  for {
    file <- filesHere
    if file.getName.endsWith(".scala")
    line <- fileLines(file)
    trimmed = line.trim
    if trimmed.matches(".*for.*")
  } yield trimmed.length

Transforming an Array[File] to Array[Int] with a for

  • first transforms the Array[File] named filesHere, which contains all files in the current directory, to one that contains only .scala files
  • For each of these it generates an Iterator[String], the result of the fileLines method
  • An Iterator offers methods next and hasNext that allow you to iterate over a collection of elements.
  • This initial iterator is transformed into another Iterator[String] containing only trimmed lines that include the substring "for".
  • Finally, for each of these, an integer length is yielded. The result of this for expression is an Array[Int] containing those lengths.

Exception handling with try expressions

Throwing exceptions

Throwing an exception in Scala looks the same as in Java. You create an exception object and then throw it with the throw keyword:

throw new IllegalArgumentException

Technically, an exception throw has type Nothing. You can use a throw as an expression even though it will never actually evaluate to anything.

Catching exceptions

try {
  val f = new FileReader("input.txt")
  // Use and close file
} catch {
  case ex: FileNotFoundException => // Handle missing file
  case ex: IOException           => // Handle other I/O error

A try-catch clause in Scala

The syntax for catch clauses was chosen for its consistency with an important part of Scala: pattern matching.

If the exception is of type FileNotFoundException, the first clause will execute. If it is of type IOException, the second clause will execute. If the exception is of neither type, the try-catch will terminate and the exception will propagate further.

The finally clause

You can wrap an expression with a finally clause if you want to cause some code to execute no matter how the expression terminates.

Although you must always surround the case statements of a catch clause in paren- theses, try and finally do not require parentheses if they contain only one expression.

For example, you could write:

try t() catch {case e: Exception => ...} finally f()
val file = new FileReader("input.txt")
try {
  // Use the file
} finally {
  file.close() // Be sure to close the file

A try-finally clause in Scala

Yielding a value

As with most other Scala control structures, try-catch-finally results in a value.

Usually finally clauses do some kind of clean up, such as closing a file. Normally, they should not change the value computed in the main body or a catch clause of the try.

def urlFor(path: String) =
  try {
    new URL(path)
  } catch {
    case e: MalformedURLException =>
      new URL("")

A catch clause that yields a value

It’s usually best to avoid returning values from finally clauses. The best way to think of finally clauses is as a way to ensure some side effect happens, such as closing an open file.

Match expressions

val firstArg = if (args.length > 0) args(0) else ""
firstArg match {
  case "salt"  => println("pepper")
  case "chips" => println("salsa")
  case "eggs"  => println("bacon")
  case _       => println("huh?")

A match expression with side effects

The default case is specified with an underscore (_), a wildcard symbol frequently used in Scala as a placeholder for a completely unknown value.

  • any kind of constant, as well as other things, can be used in cases in Scala
  • there are no breaks at the end of each alternative
  • there is no fall through from one alternative to the next
  • The most significant difference from Java’s switch, however, may be that match expressions result in a value.
val firstArg = if (!args.isEmpty) args(0) else ""
val friend =
  firstArg match {
    case "salt"  => "pepper"
    case "chips" => "salsa"
    case "eggs"  => "bacon"
    case _       => "huh?"

A match expression that yields a value

The value that results from this match expression is stored in the friend variable. Aside from the code getting shorter (in number of tokens anyway), the code now disentangles two separate concerns: first it chooses a food and then prints it.

Living without break and continue

var i = 0
var foundIt = false
while (i < args.length && !foundIt) {
  if (!args(i).startsWith("-")) {
    if (args(i).endsWith(".scala"))
      foundIt = true
  i = i + 1

Looping without break or continue

If you wanted to get rid of the vars, one approach you could try is to rewrite the loop as a recursive function.

def searchFrom(i: Int): Int =
  if (i >= args.length) -1
  else if (args(i).startsWith("-")) searchFrom(i + 1)
  else if (args(i).endsWith(".scala")) i
  else searchFrom(i + 1)
val i = searchFrom(0)

A recursive alternative to looping with vars

It uses recursion to substitute for looping. Each continue is replaced by a recursive call with i + 1 as the argument.

The Scala compiler will not actually emit a recursive function for the code. Because all of the recursive calls are in tail-call position, the compiler will generate code similar to a while loop. Each recursive call will be implemented as a jump back to the beginning of the function.

Variable Scope

  • Scala allows you to define variables of the same name in nested scopes.
  • curly braces generally introduce a new scope
  • Once a variable is defined, you can’t define a new variable with the same name in the same scope.

You can define a variable in an inner scope that has the same name as a variable in an outer scope. The following script would compile and run:

val a = 1;
  val a = 2 // Compiles just fine

When executed, the script shown previously would print 2 then 1, because the a defined inside the curly braces is a different variable, which is in scope only until the closing curly brace.

One difference to note between Scala and Java is that Java will not let you create a variable in an inner scope that has the same name as a variable in an outer scope.

By the way, the semicolon is required in this case after the first definition of a because Scala’s semicolon inference mechanism will not place one there.

The semicolon is required in this case after the first definition of a because Scala’s semicolon inference mechanism will not place one there.

Keep in mind above scope example code can be very confusing to readers, because variable names adopt new meanings in nested scopes. It is usually better to choose a new, meaningful variable name rather than to shadow an outer variable.

Refactoring imperative-style code

one advantage of side-effect-free functions is they are easier to unit test

// Returns a row as a sequence
def makeRowSeq(row: Int) =
  for (col <- 1 to 10) yield {
    val prod = (row * col).toString
    val padding = " " * (4 - prod.length)
    padding + prod
// Returns a row as a string
def makeRow(row: Int) = makeRowSeq(row).mkString
// Returns table as a string with one row per line
def multiTable() = {
  val tableSeq = // a sequence of row strings
    for (row <- 1 to 10)
      yield makeRow(row)

A functional way to create a multiplication table


Scala’s built-in control structures are minimal, but they do the job. They act much like their imperative equivalents, but because they tend to result in a value, they support a functional style, too. Just as important, they are careful in what they omit, thus leaving room for one of Scala’s most powerful features, the function literal, which will be described in the next chapter.