Pattern matching is not exhaustive in Function when it's implicitly converted to PartialFunction

127 views
Skip to first unread message

Alexander Nemish

unread,
Dec 23, 2011, 11:11:42 AM12/23/11
to scala-user
Hi,

When I use implicit conversion from PartialFunction to Function,
pattern matching becomes non-exhaustive in the following code.
Is this a bug?

object Bug {
sealed abstract class T
case object A extends T
case object B extends T

implicit def t2p(t: T => Unit) = new PartialFunction[T, Unit] {
def apply(v1: T) {t.apply(v1)}
def isDefinedAt(x: T): Boolean = true
}

def f(t: PartialFunction[T, Unit]) = t.apply(B)

// compiles without any warnings
f((t: T) => t match {
case A => ()
})

// warning: match is not exhaustive!
f(t2p((t: T) => t match {
case A => ()
}))
}

Cheers,
Alexander Nemish

Som Snytt

unread,
Dec 23, 2011, 4:29:28 PM12/23/11
to Alexander Nemish, scala-user
FWIW, I would expect this behavior: when the literal is a PartialFunction, you don't get the warning.  When you explicitly call t2p, the type of the literal is Function and you get the warning.

Analogous to:
 val p: PartialFunction[T,Unit] = { case A => () }
 val q: Function[T,Unit] = { case A => () }

In your first case, there is no warning and the implicit is not used; f takes a PF and the compiler supplies it from the literal.  That's the same as calling f(p).

Alexander Nemish

unread,
Dec 23, 2011, 5:25:09 PM12/23/11
to Som Snytt, scala-user
Thank you, Som.

My bad, I actually have a bit more complex situation:

object Bug {
 sealed abstract class T
 case object A extends T
 case object B extends T

 case class E(t: T)

 implicit def t2p(t: T => Unit) = new PartialFunction[E, Unit] {
   def apply(v1: E) {t.apply(v1.t)}
   def isDefinedAt(x: E): Boolean = true
 }

 def f(t: PartialFunction[E, Unit]) = error("Dosn't matter")

 // compiles without any warnings
 f((t: T) => t match {
   case A => ()
 })

 // warning: match is not exhaustive!
 f(t2p((t: T) => t match {
   case A => ()
 }))
}

In this case, if you comment the implicit conversion function, it won't compile, so it does use the conversion but still no warning.
Is that a bug? 

2011/12/23 Som Snytt <som....@gmail.com>

Eugen Labun

unread,
Dec 23, 2011, 8:29:19 PM12/23/11
to scala...@googlegroups.com
I believe that in both cases the inferred type of the expression ´(t: T) => t match {case A => ()}´
is ´PartialFunction[T, Unit]´.

And in both cases, in order to be a parameter of the method t2p, it gets widened to the
´Function1[T, Unit]´. Should it always trigger an exhaustiveness check?

However in the case of the explicit ´t2p´ call an exaustiveness check is performed, and in the case
of the implicitly inserted call not.

Seems to be an inconsistency to me, but may be I'm wrong somewhere.

Som Snytt

unread,
Dec 24, 2011, 7:35:25 AM12/24/11
to Alexander Nemish, scala-user
The implicit t2p sees a PF in the implicit case (hence no warning) and a Function1 in the explicit case (hence the warning).

I think the general rule is that you get a complete function unless you annotate otherwise.  Some discussion is at section 15.7
http://www.artima.com/pins1ed/case-classes-and-pattern-matching.html
and a lack of discussion in the spec section 8.5.

In the example, you get a PF because f expects to receive one. (And you wouldn't get a PF when calling g(s: String) and converting to a String.)

You can tell it what you want and get warnings back:
f(((t: T) => t match { case A => () }): Function1[T,Unit])

Is it intuitive to infer the PF for the function literal in the face of conversions to arbitrary PFs?  Maybe, if this is just composition.  Also, as to the least surprise principle, the implicit knows to handle PFs because it produces one; conversely, the caller knows the signature of f, but might be vaguely unaware of the implicit.
Reply all
Reply to author
Forward
0 new messages