Why is PartialFunction <: Function in Scala?

•
•  |
•

Question

In Scala, the `PartialFunction[A, B]` class is derived from type `Function[A, B]` (see Scala Reference, 12.3.3). However, this seems counterintuitive to me, since a `Function` (which needs to be defined for all `A`) has more stringent requirements than a `PartialFunction`, which can be undefined at some places.

The problem I've came accross was that when I have a partial function, I cannot use a `Function` to extend the partial function. Eg. I cannot do:

``````(pf orElse (_)=>"default")(x)
``````

(Hope the syntax is at least remotely right)

Why is this subtyping done reversely? Are there any reasons that I've overlooked, like the fact that the `Function` types are built-in?

BTW, it would be also nice if `Function1 :> Function0` so I needn't have the dummy argument in the example above :-)

Edit to clarify the subtyping problem

The difference between the two approaches can be emphasized by looking at two examples. Which of them is right?

One:

``````val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?
``````

Two:

``````def foo(f : (Int)=>Int) {
print(f(1))
}
val bar = new PartialFunction[Int, Int] {
def apply(x : Int) = x/2
def isDefinedAt(x : Int) = x%2 == 0
}
foo(bar) // should this be a breach of promise?
``````

OTHER TIPS

Because in Scala (as in any Turing complete language) there is no guarantee that a Function is total.

``````val f = {x : Int => 1 / x}
``````

That function is not defined at 0. A PartialFunction is just a Function that promises to tell you where it's not defined. Still, Scala makes it easy enough to do what you want

``````def func2Partial[A,R](f : A => R) : PartialFunction[A,R] = {case x => f(x)}

val pf : PartialFunction[Int, String] = {case 1 => "one"}

val g = pf orElse func2Partial{_ : Int => "default"}

scala> g(1)
res0: String = one

scala> g(2)
res1: String = default
``````

If you prefer, you can make func2Partial implicit.

`PartialFunction` has methods which `Function1` does not, therefore it is the subtype. Those methods are `isDefinedAt` and `orElse`.

Your real problem is that `PartialFunction`s are not inferred sometimes when you'd really like them to be. I'm hopeful that will be addressed at some future date. For instance this doesn't work:

``````scala> val pf: PartialFunction[String, String] = { case "a" => "foo" }
pf: PartialFunction[String,String] = <function>

scala> pf orElse { case x => "default" }
<console>:6: error: missing parameter type for expanded function
((x0\$1) => x0\$1 match { case (x @ _) => "default" })
``````

But this does:

``````scala> pf orElse ({ case x => "default" } : PartialFunction[String,String])
res5: PartialFunction[String,String] = <function>
``````

Of course you could always do this:

``````scala> implicit def f2pf[T,R](f: Function1[T,R]): PartialFunction[T,R] =
new PartialFunction[T,R] {
def apply(x: T) = f(x)
def isDefinedAt(x: T) = true
}
f2pf: [T,R](f: (T) => R)PartialFunction[T,R]
``````

And now it's more like you want:

``````scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>

scala> println(res7("a") + " " + res7("quux"))
foo default
``````