96

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.

1

2 Answers 2

171

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 =>
}
3

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.