Why is PartialFunction <: Function in Scala?

jpalecek picture jpalecek · May 30, 2009 · Viewed 7k times · Source

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?

Answer

James Iry picture James Iry · May 31, 2009

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.