6

I defined a custom extractor to get the last element of the list, as in https://stackoverflow.com/a/6697749/1092910:

object :+ {
  def unapply[A](l: List[A]): Option[(List[A], A)] = {
    if (l.isEmpty)
      None
    else 
      Some(l.init, l.last)
  }
}

Now this matches "good":

List(1, 2, 3) match {
  case init :+ last => "good"
  case head :: tail => "bad"
}

But if I add another clause, it suddenly matches "bad" now:

List(1, 2, 3) match {
  case List(7) => "never"
  case init :+ last => "good"
  case head :: tail => "bad"
}

What is the reason for this behaviour?

Community
  • 1
  • 1
  • It looks like a bug. I can try asking on one of the mailing list. – huynhjl Dec 12 '11 at 03:57
  • 1
    Compile with `scalac -print`, it seems the compiler is doing some optimization with the patterns and merged the test for `List(7)` and `head :: tail`. it first checks if it is a list of Int, then check if first element is 7, if it is not, it falls immediately to `head::tail` and matched `head::tail`. This does seem like a bug in the compiler. – markmarch Dec 12 '11 at 04:29

1 Answers1

6

It's #1697/2337 and a dozen duplicates.

https://issues.scala-lang.org/browse/SI-1697

It looks safe to say that it will not be fixed in direct fashion, but by deleting the pattern matcher for the virtpatmat implementation. Try a recent build and compile with -Yvirtpatmat, you'll get the right answer.

psp
  • 12,138
  • 1
  • 41
  • 51