55

It seems to me like the { case ... => ... } syntax for partial functions require at least one case:

scala> val pf: PartialFunction[String, String] = { case "a" => "b" } 
pf: PartialFunction[String,String] = <function1>

scala> val pf: PartialFunction[String, String] = { }                
<console>:5: error: type mismatch;
 found   : Unit
 required: PartialFunction[String,String]
       val pf: PartialFunction[String, String] = { }
                                                 ^

So, what's the best way to define an "empty" partial function? Is there a better way than "manually" overriding isDefinedAt and apply?

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 9
    There's now an empty partial function defined on the `PartialFunction` companion object. https://issues.scala-lang.org/browse/SI-4927 – Kipton Barros Aug 28 '11 at 16:31

7 Answers7

60

Map is a PartialFunction so you can do:

val undefined: PartialFunction[Any, Nothing] = Map.empty
mpilquist
  • 3,855
  • 21
  • 22
51

Since Scala 2.10 you can use:

val emptyPf = PartialFunction.empty[String, String]
Andrejs
  • 26,885
  • 12
  • 107
  • 96
8
scala> def pfEmpty[A, B] = new PartialFunction[A, B] {
     |   def apply(a: A): B = sys.error("Not supported")
     |   def isDefinedAt(a: A) = false
     | }
pfEmpty: [A, B]=> java.lang.Object with PartialFunction[A,B]

scala> val f = pfEmpty[String, String]
f: java.lang.Object with PartialFunction[String,String] = <function1>

scala> f.lift
res26: (String) => Option[String] = <function1>

scala> res26("Hola")
res27: Option[String] = None

As @didierd said in the comments, due to argument variances, a single instance can cover all possible argument types.

scala> object Undefined extends PartialFunction[Any, Nothing] {
     |   def isDefinedAt(a: Any) = false
     |   def apply(a: Any): Nothing = sys.error("undefined")
     | }
defined module Undefined

scala> val f: PartialFunction[String, String] = Undefined
f: PartialFunction[String,String] = <function1>

scala> f.lift apply "Hola"
res29: Option[String] = None
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • He says: a better way than "manually" overriding `isDefinedAt` and `apply` ;) – Nicolas Aug 25 '11 at 10:52
  • 2
    @Nicolas: Yes, define a function that does it for you. (`pfEmpty` here) ;) – missingfaktor Aug 25 '11 at 10:54
  • 1
    @Nicolas: To be honest, I missed that line when I read the question. Thanks for pointing it out! I know my question doesn't satisfy the constraint specified in the question, but anyway I am leaving it here with a hope that it might be useful for someone. – missingfaktor Aug 25 '11 at 10:58
  • 3
    Given arguments variances, a single instance could do it all: object Undefined[Any, Nothing] {... your impl ...} – Didier Dupont Aug 25 '11 at 11:00
  • 1
    There are two question marks in my post. @missingfaktor gives a great answer to the first one, and implicitly says *"not that I know of"* for the second. :-) +1! – aioobe Aug 25 '11 at 11:06
  • 2
    Shouldn't apply raise a scala.MatchError exception? That's what applying a PF that's not defined for the input usually does. – Hristo Deshev Aug 25 '11 at 11:10
  • @Hristo: Doesn't matter in this case, I _guess_. (Since `isDefinedAt` is always `false`.) – missingfaktor Aug 25 '11 at 12:18
  • 1
    Mix of the various solutions: val undefined : PartialFunction[Any, Nothing] = {case _ if false => sys.error("undefined")} – Didier Dupont Aug 25 '11 at 13:43
  • @didierd: That's good enough to post as a separate answer. :-) – missingfaktor Aug 25 '11 at 13:57
6

Stealing from everyone, a possible mix of it all :

val undefined : PartialFunction[Any, Nothing] = {case _ if false =>
  sys.error("undefined")
}
Didier Dupont
  • 29,398
  • 7
  • 71
  • 90
5

Shortest one I can think of:

{ case _ if false => "" }
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • Don't you need a `""` after the `=>` for it to be a valid `PartialFunction[String, String]`. If so, it's a bit unfortunate since it's bound to the result type of `""`, no? (Seems like an alternative would be to do `=> throw new RuntimeException()`, but that's perhaps even uglier.) What's your throughts? – aioobe Aug 25 '11 at 12:13
  • @aioobe You do. I didn't pay attention to the type of the PF. – Daniel C. Sobral Aug 25 '11 at 12:20
  • Would changing `""` to `null` (or anything else?) make it applicable for all possible partial functions (not just the ones returning `String`)? – aioobe Aug 25 '11 at 14:12
  • @aioobe No. To make it generally applicable, you have to use `error` or something similar, as they return `Nothing`. `Nothing` is the only subtype of everything. – Daniel C. Sobral Aug 25 '11 at 15:05
4

A solution (which is more a hack) is to ensure that the case is never true: { case x if x != x => sys.error("unexpected match") }

Simple curiosity, why do you need such a function?

Nicolas
  • 24,509
  • 5
  • 60
  • 66
  • I have an API that accepts a partial function, and I want to provide it with a partial function that's not defined for any argument. – aioobe Aug 25 '11 at 11:07
3

It may be interesting to know that it is planned to add an empty member to the scala library and to see how it is implemented: https://github.com/scala/scala/commit/6043a4a7ed5de0be2ca48e2e65504f56965259dc

Nicolas
  • 24,509
  • 5
  • 60
  • 66
  • It's an old question and an old answer. The current implementation can be found there: https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L246 (l.246-259) – Nicolas Sep 30 '12 at 08:42