4

Is there a full specification for pattern matching possibilities of Scala?

I am unable to fix following code:

  something match {
    case e @ (sae: ServerApiException if sae.statusCode == 401 | _: UnauthorizedException) => {
      doSomething(e)
    }
    ...
  }

(It does not compile in 2.8.1.)

TN.
  • 18,874
  • 30
  • 99
  • 157
  • Not the most descriptive or helpful question title... it's pretty vague, and people are likely to scroll right past it unless they're bored at the moment. Actually, the first line in the body would have been a better title ("Is there a full specification for pattern matching possibilities of Scala?"). – Steve Perkins Jul 08 '11 at 12:38
  • Give us a clue about what isn't working. Compilation error? Wrong result at runtime? Exception? – The Archetypal Paul Jul 08 '11 at 12:45

3 Answers3

4

Chapter 8 of the Scala Language Spec? (pdf).

More concretely, this answer may be of some assistance, that is you should be able to do something like:

case e: Exception if e.isInstanceOf[UnauthorizedException] || (e.isInstanceOf[ServerApiException] && e.asInstanceOf[ServerApiException].statusCode == 401) => {
    doSomething(e)
}
Community
  • 1
  • 1
ig0774
  • 39,669
  • 3
  • 55
  • 57
  • It does not compile, since `Exception` does not have a `statusCode` member. – TN. Jul 08 '11 at 13:12
  • @TN: Edited to add explicit cast, and actually tried to compile this version. Hardly the most beautiful code, though... – ig0774 Jul 08 '11 at 13:27
4

I'm not sure I'd write the code this way; it's hard to follow (in addition to not working in its original form).

I'd rather go for something like

def doSomething(e: Exception) = { /* whatever */ }
something match {
  case sae: ServerApiException if (sae.statusCode == 401) => doSomething(sae)
  case ue: UnauthorizedException => doSomething(ue)
}

to avoid duplicate code. Or you could use options:

(something match {
  case sae: ServerApiException if (sae.statusCode == 401) => Some(sae)
  case ue: UnauthorizedException => Some(ue)
  case _ => None
}).foreach(e => /* do something */ )

if you prefer to write the method afterwards. But I think the first way is likely the clearest.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • The options let you write `(something match { /* blah */ }).foreach(e => /* whatever */)`, where _only_ those cases that matched and got turned into `Some(x)` will make it through and be passed on in `e` in the `foreach` step. The `None` case will do nothing. So the option/foreach method does exactly the same thing as the method def version, just with the steps in a different order, and in a way that guarantees you can't use the `doSomething` method for anything else (because it isn't named--it's just the code after `e =>` in the second case). – Rex Kerr Jul 09 '11 at 21:34
  • But how to handle other cases (...)? – TN. Jul 10 '11 at 20:58
  • You didn't specify what other cases you're worried about. – Rex Kerr Jul 11 '11 at 14:33
  • There are some more exceptions. – TN. Jul 18 '11 at 14:50
  • Wrap each one you want to handle `Some` and let the others fall through to `None`. – Rex Kerr Jul 18 '11 at 17:46
  • So you mean to nest two pattern matching blocks in order to handle the other exceptions? – TN. Jul 20 '11 at 12:03
  • If you have many different cases of how to handle the exception, then the first pattern is better. The second is only a good alternative if you have two categories of exception--one that you can save in a `Some`, and another that you can ignore with a `None`. – Rex Kerr Jul 20 '11 at 15:25
3

Finally, I managed that with help of Scala Language Spec (Scala Syntax Summary):

  something match {
    case e: Exception if (e match {
      case sae: ServerApiException if sae.statusCode == 401 => true
      case _: UnauthorizedException => true
      case _ => false
    }) => {
      doSomething(e)
    }
    ...
  }
TN.
  • 18,874
  • 30
  • 99
  • 157
  • I like that better than the direction I was headed. – ig0774 Jul 08 '11 at 13:30
  • I guess the actual context might be more complex, but this specific example is perhaps more straightforward as `something match { case sae:ServerApiException if sae.statusCode == 401 => doSomething(sae); case ue: UnauthorizedException => doSomething(ue); }` – The Archetypal Paul Jul 08 '11 at 13:54
  • Yes, the actual code `doSomething` is more complex and therefore I was searching for a 'better' solution. – TN. Jul 08 '11 at 14:04