Question

I was trying to debug why some partial function composition were not working when I noticed that depending on how you instantiate the partial function you get different results.

When you're using the syntactic sugar method it all works as expected:

scala> val pf1:PartialFunction[Any,Unit] = {case "a" => println("AAA")}
pf1: PartialFunction[Any,Unit] = <function1>

scala> val pf2:PartialFunction[Any,Unit] = {case "b" => println("BBB")}
pf2: PartialFunction[Any,Unit] = <function1>

scala> val pf = pf1 orElse pf2
pf: PartialFunction[Any,Unit] = <function1>

scala> pf("a")
AAA

scala> pf("b")
BBB

However, if you use the PartialFunction object it doesn't work anymore.

scala> val pf1 = PartialFunction[Any,Unit]{case "a" => println("AAA")}
pf1: PartialFunction[Any,Unit] = <function1>

scala> val pf2 = PartialFunction[Any,Unit]{case "b" => println("BBB")}
pf2: PartialFunction[Any,Unit] = <function1>

scala> val pf = pf1 orElse pf2
pf: PartialFunction[Any,Unit] = <function1>

scala> pf("a")
AAA

scala> pf("b")
scala.MatchError: b (of class java.lang.String)
at $anonfun$1.apply(<console>:7)

Why is that? You usually grow to expect that the apply method of an Object behaves like the constructor of the Class.

Was it helpful?

Solution 2

As others noted, PartialFunction.apply converts an ordinary function into a partial function.

The only reasonable way to do this, since the domain of the ordinary function is unknown (as far as PartialFunction.apply is concerned), is to create a partial function defined everywhere.

So when you write PartialFunction[Any,Unit] { case "a" => println("AAA") }, you're actually creating two partial functions: the one passed into the apply method and the one returned by the apply method. They're almost the same, except that the returned function is defined everywhere and not just at "a".

OTHER TIPS

The documentation says that the apply method of the Object converts an ordinary function to a partial one, but it does not detail how. Apparently it makes isDefinedAt to return true at all times:

scala> val pf1 = PartialFunction[Any,Unit]{case "a" => println("AAA")}
pf1: PartialFunction[Any,Unit] = <function1>

scala> pf1.isDefinedAt("a")
res14: Boolean = true

scala> pf1.isDefinedAt("b")
res15: Boolean = true

This will result in the pf1 always capturing the input. So I guess the conclusion is be careful how you instantiate a partial function.

The apply method in the PartialFunction Object converts ordinary function to partial one. Read the documentation here So the partial function that was declared is treated as an ordinary function and typed as PartialFunction. The domain for this function becomes all the domain of an ordinary function regardless of what is implemented there. So, pf1 ends up consuming all the input and never calling the orElse function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top