How to pattern match multiple values in Scala?

ScalaPattern Matching

Scala Problem Overview


Let's say I want to handle multiple return values from a remote service using the same code. I don't know how to express this in Scala:

code match {
  case "1" => // Whatever
  case "2" => // Same whatever
  case "3" => // Ah, something different
}

I know I can use Extract Method and call that, but there's still repetition in the call. If I were using Ruby, I'd write it like this:

case code
when "1", "2"
  # Whatever
when "3"
  # Ah, something different
end

Note that I simplified the example, thus I don't want to pattern match on regular expressions or some such. The match values are actually complex values.

Scala Solutions


Solution 1 - Scala

You can do:

code match {
  case "1" | "2" => // whatever
  case "3" =>
}

Note that you cannot bind parts of the pattern to names - you can't do this currently:

code match {
  case Left(x) | Right(x) =>
  case null =>
}

Solution 2 - Scala

The other answer correctly says that currently there is no way to pattern-match multiple alternatives while extracting values at the same time. I'd like to share a coding pattern with you that comes close to doing this.

Scala allows you to pattern-match alternatives without extracting values, e.g. case Dog(_, _) | Cat(_, _) => ... is legal. Using this, you can simply extract the values yourself within the case block.

Here's a somewhat contrived example:

abstract class Animal
case class Dog(age: Int, barkLevel: Int) extends Animal
case class Cat(apparentAge: Int, cutenessLevel: Int) extends Animal

val pet: Animal = Dog(42, 100)

// Assume foo needs to treat the age of dogs and the apparent age
// of cats the same way.
// Same holds for bark and cuteness level.
def foo(pet: Animal): Unit = pet match {
  case animal@(Dog(_, _) | Cat(_, _)) =>

    // @unchecked suppresses the Scala warning about possibly
    // non-exhaustiveness even though this match is exhaustive
    val (agelike, level) = (animal: @unchecked) match {
      case Dog(age, barkLevel) => (age, barkLevel)
      case Cat(apparentAge, cutenessLevel) => (apparentAge, cutenessLevel)
    }

    ???
}

Assume that ??? actually stands for doing something that is equal for dogs and cats. Without this coding pattern, you would need to have two cases, one for dogs and one for cats, forcing you to duplicate code or at least to outsorce code into a function.

Generally, the coding pattern above is suitable if you have sibling case classes that share fields that behave identically only for some algorithms. In those cases, you cannot extract those fields to a common superclass. Still, you would like to pattern-match in a uniform way on those fields in the algorithms that treat them equally. This you can do as shown above.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFrançois BeausoleilView Question on Stackoverflow
Solution 1 - Scalaaxel22View Answer on Stackoverflow
Solution 2 - ScalaComFreekView Answer on Stackoverflow