Scala pattern match is not exhaustive on nested case classes

215 views
Skip to first unread message

Sanj Sahayam

unread,
Jan 11, 2016, 8:46:59 AM1/11/16
to scala-user
I've got a case class hierarchy to encode some request and processing errors:

sealed trait OpError
sealed trait RequestErrorType
sealed trait ProcessingErrorType

final case class InvalidEndpoint(reason: String) extends RequestErrorType
final case class InvalidParameters(reason: String) extends RequestErrorType

final case class InvalidFormat(response: String) extends ProcessingErrorType
final case class EntityNotFound(id: Long) extends ProcessingErrorType

final case class RequestError(errorType: RequestErrorType) extends OpError
final case class ProcessingError(errorType: ProcessingErrorType) extends OpError

If I write a simple match across all patterns:


def printMatches(error: OpError): Unit = error match {
   
case RequestError(InvalidEndpoint(reason)) => //print something
   
case RequestError(InvalidParameters(reason)) => //print something
   
case ProcessingError(InvalidFormat(format)) => //print something
   
case ProcessingError(EntityNotFound(entityId)) => //print something
 
}


the compiler gives me a warning about missing match:


match may not be exhaustive.
 
It would fail on the following input: ProcessingError(_)
 
def printMatches(error: OpError): Unit = error match {

But ProcessingError takes in a ProcessingErrorType with only two extensions: InvalidFormat and EntityNotFound, both which are accounted for in the pattern match. Am I missing a match or could this be a compiler bug? I'm using Scala 2.11.7.


Note: I've already asked this question on SO without any resolution.

Oliver Ruebenacker

unread,
Jan 11, 2016, 10:16:04 AM1/11/16
to Sanj Sahayam, scala-user

     Hello,

  ProcessingError(null)?

     Best, Oliver

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

Jasper-M

unread,
Jan 11, 2016, 10:47:39 AM1/11/16
to scala-user
Adding a `case ProcessingError(_)` fixes the warning, but if you reverse the order of the cases you get "It would fail on the following input: RequestError(_)".
So I would think it is a bug.

Op maandag 11 januari 2016 14:46:59 UTC+1 schreef Sanj Sahayam:

John

unread,
Jan 15, 2016, 11:42:09 PM1/15/16
to scala-user
I don't think the second message is a bug. It would fail on OpError(null) and OpError(RequestError(null))

-John

David Barri

unread,
Jan 16, 2016, 1:06:34 AM1/16/16
to scala-user
Yeah, there are quite a few bugs in exhaustiveness checking.
Sometimes it gives you false errors when everything's good...
Sometimes it tells you everything's good where there are holes...
As a workaround, try just rearranging the order of your cases.

I think bugs in exhaustiveness checking are one of the most important and critical things there are. We all go about trumpeting how glorious it is to have an expressive static types such that the compiler omits the need for entire classes of tests but if you take a look at the open bugs you can see we're all standing on thin ice.

Worst is that no one seems to give a shit. (Specifically: the open bugs haven't been treated as critical and resolved quickly; they just rot, open.)

Woefully and with gradually growing resentment,
David

David Barri

unread,
Jan 16, 2016, 1:20:17 AM1/16/16
to scala-user
> with gradually growing resentment

Ok that's a bit harsh. I'll reword that: "with ever-dwindling optimism"

Sanj Sahayam

unread,
Jan 16, 2016, 2:45:21 AM1/16/16
to scala-user
I don't think null plays into this. I can compile the following just fine without null checks:

  sealed trait InnerBlah
  final case class Blee(value: String) extends InnerBlah
  final case class Blue(value: String) extends InnerBlah


  sealed trait Blah
  final case class OneBlah(value: InnerBlah) extends Blah

  def printBlah(blah: Blah): Unit = blah match {
    case OneBlah(Blee(v)) => println(s"got a Blee($v)")
    case OneBlah(Blue(v)) => println(s"got a Blah($v)")
  }

John

unread,
Jan 17, 2016, 2:09:57 AM1/17/16
to scala-user
You're right, it looks like I jumped in without really understanding the situation    printBlah(OneBlah(null)) does throw  scala.MatchErrorfor me with 2.11.7 for whatever that's worth.  (So the match is not exhaustive, even though, unlike in your example from the first post in this thread, the compiler chooses not to warn you about it.)

-John

Richard Bradley

unread,
Jan 18, 2016, 5:58:41 AM1/18/16
to scala-user
+1 from me.

While it doesn't seem to be very important to the core team, I think they would accept PRs to address these issues.


Adriaan Moors

unread,
Jan 18, 2016, 2:40:35 PM1/18/16
to Richard Bradley, scala-user
Yes, please don't assume malice when lack of time suffices as an explanation. We're pretty busy rewriting most of the backend and optimizer for 2.12. Thank you for your understanding. 

David Barri

unread,
Jan 18, 2016, 3:13:14 PM1/18/16
to Adriaan Moors, Richard Bradley, scala-user
I don't think anyone is assuming malice. The disappointment is that is isn't receiving higher priority. Bugs in exhaustiveness checking mean that we can't rely on compilation to prove that our programs are correct - that's way more critical and important than a new backend, new optimiser, SAMs and all the other (good) stuff in 2.12.

--
You received this message because you are subscribed to a topic in the Google Groups "scala-user" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-user/FGUwP38pQ3o/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-user+...@googlegroups.com.

Sanj Sahayam

unread,
Jan 18, 2016, 10:15:42 PM1/18/16
to scala-user
 As a general rule I don't use or return nulls. I prefer to wrap them in Option or Either, so I hadn't thought about what would happen when you use null in a pattern match. Thanks for the insight. :)

Sanj Sahayam

unread,
Jan 18, 2016, 10:18:09 PM1/18/16
to scala-user
I agree that exhaustiveness checking is important. If you can't trust the compiler... well... you can't trust the compiler.

Naftoli Gugenheim

unread,
Jan 18, 2016, 10:29:35 PM1/18/16
to Sanj Sahayam, scala-user

Same point for all the soundness bugs in the database


--

Sanj Sahayam

unread,
Jan 25, 2016, 4:05:16 AM1/25/16
to scala-user, sanjsm...@gmail.com

Jason Zaugg

unread,
Jan 27, 2016, 1:42:35 AM1/27/16
to David Barri, Adriaan Moors, Richard Bradley, scala-user
On Tue, Jan 19, 2016 at 6:13 AM David Barri <japg...@gmail.com> wrote:
I don't think anyone is assuming malice. The disappointment is that is isn't receiving higher priority. Bugs in exhaustiveness checking mean that we can't rely on compilation to prove that our programs are correct - that's way more critical and important than a new backend, new optimiser, SAMs and all the other (good) stuff in 2.12.

I've made some progress in this area in https://github.com/scala/scala/pull/4919

David: If you have any other exhaustivity/reachability related issues in JIRA that have I haven't mentioned in this pull request, please mention me on the ticket and I'll see if this patch fixes them too.

Thanks (both for the bug reports and patience!)

-jason

David Barri

unread,
Jan 29, 2016, 6:16:32 PM1/29/16
to scala-user, japg...@gmail.com, adr...@typesafe.com, richard.brad...@gmail.com
I've made some progress in this area in https://github.com/scala/scala/pull/4919

David: If you have any other exhaustivity/reachability related issues in JIRA that have I haven't mentioned in this pull request, please mention me on the ticket and I'll see if this patch fixes them too.

I'm relived to see this get attention and very happy to see this fixed. Many, many thanks Jason!!
Reply all
Reply to author
Forward
0 new messages