I’ve gotten into the habit (form any of years) of simply never using type arguments in patterns (case Foo[T](x, y)
) because I thought they didn’t work. Recently, I discovered that they in fact do work, just not in the way you might think.
class Foo[T] {
def unapply(x: Int): Option[Int] = Some(4)
}
object Foo {
def unapply[T](x: T): Option[Int] = Some(5)
}
1 match {
case Foo(x) => println(x + " then")
}
1 match {
case Foo[Int](x) => println(x)
}
// prints
// 5 then
// 4
I can’t seem to find the history of this IMHO very surprising behavior. I found this bug, but it is still open. I also found some discussion by @LPTK here. Nieither seems to acknowledge that you can (kind of) have type parameters in patterns, just not in the way that you would expect.
Also note some other surprises – this compiles:
class Foo[T]() {
def unapply(x: Int): Option[Int] = Some(4)
}
1 match {
case Foo[Int](x) => println(x)
}
but this doesn’t
class Foo[T](x: Int = 1) {
def unapply(x: Int): Option[Int] = Some(4)
}
1 match {
case Foo[Int](x) => println(x) // error: missing arguments for constructor Foo in class Foo
}
but you can of course to
class Foo[T](x: Int = 1) {
def unapply(x: Int): Option[Int] = Some(4)
}
val M = Foo[Int]()
1 match {
case M(x) => println(x + " then")
}
It seems to be that the unsurprising thing would be for type arguments in a pattern to be interpreted as type arguments to the call to unapply
. I think there must be some reason why it doesn’t work this way, and I’m hoping someone here might know why. Thanks!