Scala match/case expressions (syntax, examples)

This is a lesson on Scala match/case expressions from my book, Hello, Scala.

Scala match expressions

Scala has a concept of a match expression. In the most simple case you can use a match expression like a Java switch statement:

// i is an integer
i match {
    case 1  => println("January")
    case 2  => println("February")
    case 3  => println("March")
    case 4  => println("April")
    case 5  => println("May")
    case 6  => println("June")
    case 7  => println("July")
    case 8  => println("August")
    case 9  => println("September")
    case 10 => println("October")
    case 11 => println("November")
    case 12 => println("December")
    // catch the default with a variable so you can print it
    case _  => println("Invalid month")
}

As shown, with a match expression you write a number of case statements that you use to match possible values. In this example I match the integer values 1 through 12. Any other value falls down to the _ case, which is the catch-all, default case.

match expressions are nice because they also return values, so rather than directly printing a string as in that example, you can assign the string result to a new value:

val monthName = i match {
    case 1  => "January"
    case 2  => "February"
    case 3  => "March"
    case 4  => "April"
    case 5  => "May"
    case 6  => "June"
    case 7  => "July"
    case 8  => "August"
    case 9  => "September"
    case 10 => "October"
    case 11 => "November"
    case 12 => "December"
    case _  => "Invalid month"
}

Using a match expression to yield a result like this is a common use.

Aside: A quick look at Scala methods

Scala also makes it easy to use a match expression as the body of a method. I haven’t shown how to write Scala methods yet, so as a brief introduction, let me share a method named convertBooleanToStringMessage that takes a Boolean value and returns a String:

def convertBooleanToStringMessage(bool: Boolean): String = {
    if (bool) "true" else "false"        
}

Hopefully you can see how that method works, even though I won’t go into its details. These examples show how it works when I give it the Boolean values true and false:

scala> val answer = convertBooleanToStringMessage(true)
answer: String = true

scala> val answer = convertBooleanToStringMessage(false)
answer: String = false

Using a match expression as the body of a method

Now that you’ve seen an example of a Scala method, here’s a second example that works just like the previous one, taking a Boolean value as an input parameter and returning a String message. The big difference is that this method uses a match expression for the body of the method:

def convertBooleanToStringMessage(bool: Boolean): String = bool match {
    case true => "you said true"
    case false => "you said false"
}

The body of that method is just two case statements, one that matches true and another that matches false. Because those are the only possible Boolean values, there’s no need for a default case statement.

This is how you call that method and then print its result:

val result = convertBooleanToStringMessage(true)
println(result)

Using a match expression as the body of a method is also a common use.

Handling alternate cases

Scala match expressions are extremely powerful, and I’ll demonstrate a few other things you can do with them.

match expressions let you handle multiple cases in a single case statement. To demonstrate this, imagine that you want to evaluate “boolean equality” like the Perl programming language handles it: a 0 or a blank string evaluates to false, and anything else evaluates to true. This is how you write a method using a match expression that evaluates to true and false in the manner described:

def isTrue(a: Any) = a match {
    case 0 | "" | false => false
    case _ => true
}

Because the input parameter a is defined to be the Any type — which is the root of all Scala classes, like Object in Java — this method works with any data type that’s passed in:

scala> isTrue(0)
res0: Boolean = false

scala> isTrue("")
res1: Boolean = false

scala> isTrue(1.1F)
res2: Boolean = true

scala> isTrue(new java.io.File("/etc/passwd"))
res3: Boolean = true

The key part of this solution is that this one case statement lets both 0 and the empty string evaluate to false:

case 0 | "" => false

Before I move on, here’s another example that shows many matches in each case statement:

i match {
    case 1 | 3 | 5 | 7 | 9 => println("odd")
    case 2 | 4 | 6 | 8 | 10 => println("even")
    case _ => println("some other number")
}

Here’s another example that shows how to handle multiple strings in multiple case statements:

cmd match {
    case "start" | "go" => println("starting")
    case "stop" | "quit" | "exit" => println("stopping")
    case _ => println("doing nothing")
}

Using if expressions in case statements

Another great thing about match expressions is that you can use if expressions in case statements for powerful pattern matching. In this example the second and third case statements both use if expressions to match ranges of numbers:

count match {
    case 1 => println("one, a lonely number")
    case x if x == 2 || x == 3 => println("two's company, three's a crowd")
    case x if x > 3 => println("4+, that's a party")
    case _ => println("i'm guessing your number is zero or less")
}

Scala doesn’t require you to use parentheses in the if expressions, but you can use them if you think that makes them more readable:

count match {
    case 1 => println("one, a lonely number")
    case x if (x == 2 || x == 3) => println("two's company, three's a crowd")
    case x if (x > 3) => println("4+, that's a party")
    case _ => println("i'm guessing your number is zero or less")
}

You can also write the code on the right side of the => on multiple lines if you think is easier to read. Here’s one example:

count match {
    case 1 => 
        println("one, a lonely number")
    case x if x == 2 || x == 3 => 
        println("two's company, three's a crowd")
    case x if x > 3 => 
        println("4+, that's a party")
    case _ => 
        println("i'm guessing your number is zero or less")
}

Here’s a variation of that example that uses parentheses

count match {
    case 1 => {
        println("one, a lonely number")
    }
    case x if x == 2 || x == 3 => {
        println("two's company, three's a crowd")
    }
    case x if x > 3 => {
        println("4+, that's a party")
    }
    case _ => {
        println("i'm guessing your number is zero or less")
    }
}

Here are a few other examples of how you can use if expressions in case statements. First, another example of how to match ranges of numbers:

i match {
  case a if 0 to 9 contains a => println("0-9 range: " + a)
  case b if 10 to 19 contains b => println("10-19 range: " + a)
  case c if 20 to 29 contains c => println("20-29 range: " + a)
  case _ => println("Hmmm...")
}

Lastly, this example shows how to reference class fields in if expressions:

stock match {
  case x if (x.symbol == "XYZ" && x.price < 20) => buy(x)
  case x if (x.symbol == "XYZ" && x.price > 50) => sell(x)
  case x => doNothing(x)
}

Even more ...

match expressions are very powerful, and there are even more things you can do with them. Please see my other books — Scala Cookbook and Functional Programming, Simplified — for even more details.