3

While writing a Specs2 specification for an Actor I got a somewhat puzzling MatchError for composition of several partial functions.

A minimal example:

val testPf1 = PartialFunction[Any, Boolean]{ case 2 ⇒ true }
val testPf2 = PartialFunction[Any, Boolean]{ case 1 ⇒ true }
val testPf = testPf1 orElse testPf2
testPf.isDefinedAt(1)
testPf.isDefinedAt(2)
testPf(1)
testPf(2)

leads to the output:

testPf1: PartialFunction[Any,Boolean] = <function1>
testPf2: PartialFunction[Any,Boolean] = <function1>
testPf: PartialFunction[Any,Boolean] = <function1>
res0: Boolean = true
res1: Boolean = true
scala.MatchError: 1 (of class java.lang.Integer)
    at com.dasgip.controller.common.informationmodel.programming.parametersequence.A$A161$A$A161$$anonfun$testPf1$1.apply(PFTest.sc0.tmp:33)
    at com.dasgip.controller.common.informationmodel.programming.parametersequence.A$A161$A$A161$$anonfun$testPf1$1.apply(PFTest.sc0.tmp:33)
    at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PFTest.sc0.tmp:243)
    at scala.PartialFunction$OrElse.apply(PFTest.sc0.tmp:163)
    at #worksheet#.#worksheet#(PFTest.sc0.tmp:36)

That totally confused me. If for a given input isDefinedAt on the composition of two partial functions returns true, I would expect that I can also apply it to the same input.

Sascha Kolberg
  • 7,092
  • 1
  • 31
  • 37

1 Answers1

5

Hence, I learned that changing the first two lines to:

val testPf1: PartialFunction[Any, Boolean] = { case 2 ⇒ true }
val testPf2: PartialFunction[Any, Boolean] = { case 1 ⇒ true }

makes the composition work as expected.

The reason for the MatchError was that with

PartialFunction[Any, Boolean]{ case 2 => true } 

I actually seem to be calling PartialFunction.apply, which converts a Function1 to a PartialFunction.

So that the statement expands to

 PartialFunction.apply[Any, Boolean](_ match { case 2 => true })

and then converted to

{ case x => f(x) }

which, of course, will always return true for isDefined and throw a MatchError on input not matched by f.

Sascha Kolberg
  • 7,092
  • 1
  • 31
  • 37
  • That's a good one. I've only used the corrected form; always asking what is the expected type of the case block or "pattern matching anon fun" since that determines whether you get a PF. I think the apply method here is misnamed; it was introduced in the very good PF revamp; but this is a bad gotcha. Boy, naming is really hard. – som-snytt Oct 01 '15 at 17:34