Search code examples
scalapartialfunction

Magic PartialFunction in Scala


I don't think this code should work, but it does (in Scala 2.10):

scala>     ((i: Int) => i.toString match {
     |        case s if s.length == 2 => "A two digit number"
     |        case s if s.length == 3 => "A three digit number"
     |     }): PartialFunction[Int,String]
res0: PartialFunction[Int,String] = <function1>

// other interactions omitted

scala> res0.orElse(PartialFunction((i: Int) => i.toString))
res5: PartialFunction[Int,String] = <function1>

scala> res5(1)
res6: String = 1

How does it work? I would expect a MatchError to be thrown inside res0.

The Scala language specification does not seem to explicitly document how res0 should be interpreted.


Solution

  • The trick is that the compiler is not interpreting your definition as a total function converted to a partial function -- it's actually creating a partial function in the first place. You can verify by noting that res0.isDefinedAt(1) == false.

    If you actually convert a total function to a partial function, you will get the behavior you expected:

    scala> PartialFunction((i: Int) => i.toString match {
         |       case s if s.length == 2 => "A two digit number"
         |       case s if s.length == 3 => "A three digit number"
         |     })
    res0: PartialFunction[Int,String] = <function1>
    
    scala> res0 orElse ({ case i => i.toString }: PartialFunction[Int, String])
    res1: PartialFunction[Int,String] = <function1>
    
    scala> res1(1)
    scala.MatchError: 1 (of class java.lang.String)
    // ...
    

    In this example, PartialFunction.apply treats its argument as a total function, so any information about where it's defined is lost.