Pattern type is incompatible with expected type

192 views
Skip to first unread message

Piotr Kołaczkowski

unread,
May 19, 2011, 3:03:06 PM5/19/11
to scala...@googlegroups.com
Hi,

class C[T]
case class CC[T](value: C[T])

class Test[T] {
def method(arg: Any) {
arg match {
case CC(x: C[T]) => println("ok")
}
}
}

error: pattern type is incompatible with expected type;
found : test.C[T]
required: test.C[Any]
Note: T <: Any, but class C is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
case CC(x: C[T]) => println("ok")

Why? Is it a bug or my misunderstanding how pattern matching works?
I know I should get an unchecked warning, because due to erasure it
cannot be verified at runtime that CC is really of type CC[T], but why a
compile time error?

Regards,
Piotr

Paul Phillips

unread,
May 19, 2011, 3:55:55 PM5/19/11
to Piotr Kołaczkowski, scala...@googlegroups.com
On 5/19/11 12:03 PM, Piotr Kołaczkowski wrote:
> class Test[T] {
> def method(arg: Any) {
> arg match {
> case CC(x: C[T]) => println("ok")
> }
> }
> }

The type of a pattern must conform to the expected type. In this case
the explicit type C[T] does not conform to the type of the case class
parameter.

Write case CC(x: C[t]) and it will compile and infer what it can for the
type parameter. If you want a type it doesn't infer, then you can cast
it in the pattern body: the pattern matcher is not intended as a general
purpose casting mechanism.

> But this does not:
>
> trait Base[T]
> case object Derived extends Base[Int]
>
> class Test[T] {
> def method(arg: Base[T]) {
> arg match {
> case Derived => println("ok")
> }
> }
> }

The type of a pattern must conform to the expected type. In this case
the type of Derived does not conform to Base[T] (where T is some fixed
but unknown T.) You can always make such matches compile anyway:

(arg: Any) match { ....

because everything conforms to Any.

Sonnenschein

unread,
May 19, 2011, 3:59:35 PM5/19/11
to scala-user
Hi, for instance the following compiles:

arg match {
case CC(x) => println(x)
}

Piotr Kołaczkowski

unread,
May 20, 2011, 3:30:44 AM5/20/11
to scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org
W dniu 2011-05-19 21:55, Paul Phillips pisze:

> On 5/19/11 12:03 PM, Piotr Kołaczkowski wrote:
>> class Test[T] {
>> def method(arg: Any) {
>> arg match {
>> case CC(x: C[T]) => println("ok")
>> }
>> }
>> }
>
> The type of a pattern must conform to the expected type. In this case
> the explicit type C[T] does not conform to the type of the case class
> parameter.

But it does - CC[T] is the only class here that can accept an argument
of type C[T]. So I would expect the type inferencer to infer CC[T],
basing on the type of the argument. Just as it happens in this case,
which compiles perfectly:

case class CC[T](value: T)

class Test[T] {
def method(arg: Any) {
arg match {

case CC(x: T) => println("ok")
}
}
}


>
> Write case CC(x: C[t]) and it will compile and infer what it can for the
> type parameter.


This is not a solution, because it will infer CC[Any], and x: C[Any],
and I don't want it to.

If you want a type it doesn't infer, then you can cast
> it in the pattern body:

Right, forcing a cast from C[Any] to C[T] on the right side works, but I
feel it is then a slight deficiency of the current pattern matching
implementation. BTW: you can write it even shorter: CC(x) and x will be
automatically of type C[Any].


> the pattern matcher is not intended as a general
> purpose casting mechanism.

Well, this is debatable. I thought you designed Scala to be as much
orthogonal as possible. If typecasting the arguments on the left side
works for any "simple" type like T, how is C[T] different, except making
it harder at the compiler implementation side?

Uh, oh, now I noticed it is already implemented and works in this case:

scala> class C[T]
defined class C

scala> case class CC[T](value: C[T])
defined class CC

scala> val a = new C[Int]
a: C[Int] = C@13e55db

scala> CC(a) // look ma, here it doesn't have a problem
res0: CC[Int] = CC(C@13e55db)


>
>> But this does not:
>>
>> trait Base[T]
>> case object Derived extends Base[Int]
>>
>> class Test[T] {
>> def method(arg: Base[T]) {
>> arg match {
>> case Derived => println("ok")
>> }
>> }
>> }
>
> The type of a pattern must conform to the expected type. In this case
> the type of Derived does not conform to Base[T] (where T is some fixed
> but unknown T.)

Define exactly what it means "conforms". I believe the main purpose of
pattern matching is to find a pattern the object being tested matches.
So by definition, there will be patterns that don't match. I understood
that the compiler has to assure that every pattern has some chances to
be matched, so matching against totally unrelated types is treated as
error. But in this case, for sure there exist some T (exactly = Int)
such that Derived is a subclass of Base[T]. Because the compiler doesn't
really know what the T is at the moment of compilation, it cannot prove
my code is wrong. Therefore it should compile. And if it should not
compile, the first snippet using "case x: Derived =>" shouldn't too.

Anyway, thanks for the (x: Any) trick to make the compiler shut up. :

Regards,
Piotr

Piotr Kołaczkowski

unread,
May 20, 2011, 3:30:57 AM5/20/11
to scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org
W dniu 2011-05-19 21:55, Paul Phillips pisze:
> On 5/19/11 12:03 PM, Piotr Kołaczkowski wrote:
>> class Test[T] {
>> def method(arg: Any) {
>> arg match {
>> case CC(x: C[T]) => println("ok")
>> }
>> }
>> }
>
> The type of a pattern must conform to the expected type. In this case
> the explicit type C[T] does not conform to the type of the case class
> parameter.

But it does - CC[T] is the only class here that can accept an argument

of type C[T]. So I would expect the type inferencer to infer CC[T],
basing on the type of the argument. Just as it happens in this case,
which compiles perfectly:

case class CC[T](value: T)

class Test[T] {
def method(arg: Any) {
arg match {

case CC(x: T) => println("ok")
}
}
}


>


> Write case CC(x: C[t]) and it will compile and infer what it can for the
> type parameter.

This is not a solution, because it will infer CC[Any], and x: C[Any],
and I don't want it to.

If you want a type it doesn't infer, then you can cast


> it in the pattern body:

Right, forcing a cast from C[Any] to C[T] on the right side works, but I

feel it is then a slight deficiency of the current pattern matching
implementation. BTW: you can write it even shorter: CC(x) and x will be
automatically of type C[Any].

> the pattern matcher is not intended as a general
> purpose casting mechanism.

Well, this is debatable. I thought you designed Scala to be as much

orthogonal as possible. If typecasting the arguments on the left side
works for any "simple" type like T, how is C[T] different, except making
it harder at the compiler implementation side?

Uh, oh, now I noticed it is already implemented and works in this case:

scala> class C[T]
defined class C

scala> case class CC[T](value: C[T])
defined class CC

scala> val a = new C[Int]
a: C[Int] = C@13e55db

scala> CC(a) // look ma, here it doesn't have a problem
res0: CC[Int] = CC(C@13e55db)


>


>> But this does not:
>>
>> trait Base[T]
>> case object Derived extends Base[Int]
>>
>> class Test[T] {
>> def method(arg: Base[T]) {
>> arg match {
>> case Derived => println("ok")
>> }
>> }
>> }
>
> The type of a pattern must conform to the expected type. In this case
> the type of Derived does not conform to Base[T] (where T is some fixed
> but unknown T.)

Define exactly what it means "conforms". I believe the main purpose of

Daniel Sobral

unread,
May 20, 2011, 10:30:37 AM5/20/11
to Paul Phillips, Piotr Kołaczkowski, scala...@googlegroups.com
2011/5/19 Paul Phillips <pa...@improving.org>:

>> But this does not:
>>
>> trait Base[T]
>> case object Derived extends Base[Int]
>>
>> class Test[T] {
>>   def method(arg: Base[T]) {
>>     arg match {
>>       case Derived => println("ok")
>>     }
>>   }
>> }
>
> The type of a pattern must conform to the expected type.  In this case
> the type of Derived does not conform to Base[T] (where T is some fixed
> but unknown T.)

But the following works:

scala> class Test {
| def method[T](arg: Base[T]) {


| arg match {
| case Derived => println("ok")
| }
| }
| }

defined class Test

Why is it that just moving [T] from the class to the method makes a difference?

--
Daniel C. Sobral

I travel to the future all the time.

Paul Phillips

unread,
May 20, 2011, 11:34:08 AM5/20/11
to Daniel Sobral, Piotr Kołaczkowski, scala...@googlegroups.com
On 5/20/11 7:30 AM, Daniel Sobral wrote:
> Why is it that just moving [T] from the class to the method makes a difference?

I don't have time to attempt an explanation, but method and class type
parameters are treated completely differently during pattern matching.
See papers by emir and section 8.4 of the spec.

Paul Phillips

unread,
May 20, 2011, 11:58:49 AM5/20/11
to Piotr Kołaczkowski, scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org
On 5/20/11 12:30 AM, Piotr Kołaczkowski wrote:
> scala> case class CC[T](value: C[T])
> defined class CC
>
> scala> val a = new C[Int]
> a: C[Int] = C@13e55db
>
> scala> CC(a) // look ma, here it doesn't have a problem
> res0: CC[Int] = CC(C@13e55db)

I don't have the least idea what this is supposed to demonstrate to ma.
It's not even a pattern match.

I'll have to ask you to reformulate your issues in terms of the
specification if you want to continue this, because regardless of what
you think it should do, what the spec says it should do is what is
relevant to the implementation.

> Because the compiler doesn't
> really know what the T is at the moment of compilation, it cannot prove
> my code is wrong. Therefore it should compile.

This is absolutely contrary to the design. It is not a goal of the
pattern matcher, or of type systems in general, to never issue errors on
correct programs. In fact it is provably impossible: all type systems
exclude some typesafe programs. The set of programs which pass a
typechecker are not "all those which cannot be proved wrong", they are
"all those which can be proved typesafe."

Daniel Sobral

unread,
May 20, 2011, 5:11:56 PM5/20/11
to Piotr Kołaczkowski, scala...@googlegroups.com
2011/5/20 Piotr Kołaczkowski <pkol...@elka.pw.edu.pl>:

>
> Define exactly what it means "conforms". I believe the main purpose of
> pattern matching is to find a pattern the object being tested matches. So by
> definition, there will be patterns that don't match. I understood that the
> compiler has to assure that every pattern has some chances to be matched, so
> matching against totally unrelated types is treated as error. But in this
> case, for sure there exist some T (exactly = Int) such that Derived is a
> subclass of Base[T]. Because the compiler doesn't really know what the T is
> at the moment of compilation, it cannot prove my code is wrong. Therefore it
> should compile. And if it should not compile, the first snippet using "case
> x: Derived =>" shouldn't too.

The question is how much help should the compiler provide. Take this:

5 match { case "abc" => true }

Should the compiler compile this, or should it complain that match is
impossible? This could be argued either way, but the benefit of static
typing is that the compiler can complain, so the bias here is to
complain whenever possible.

If you do this:

class Test[T] {
def method(arg: Base[T]) {
arg match {
case Derived => println("ok")
}
}
}

What you (and I, to be honest) thought happened was the compiler asked
if "Base[T]" can be "Derived". What actually happens is that the
compiler checks if "Derived" is a "Base[T]", and it is not. That is,
you cannot state that Derived <: Base[T] for all T.

You can make it work with:

class Test[T] {
def method(arg: Base[T]) {

(arg: Base[_]) match {


case Derived => println("ok")
}
}
}

which tells the compiler that "arg" might be any Base, really. The
curious thing is that the following works:

def method[T](arg: Base[T]) {


arg match {
case Derived => println("ok")
}
}

As it happens, this case is covered by this in the specification:

Let T be the type of the selector expression e and let a 1 , . . . , a
m be the type param-
eters of all methods enclosing the pattern matching expression. For
every a i , let L i
be its lower bound and Ui be its higher bound. Every pattern p ∈ {p 1
, , . . . , p n } can
be typed in two ways. First, it is attempted to type p with T as its
expected type. If
this fails, p is instead typed with a modified expected type T' which
results from T
by replacing every occurrence of a type parameter a i by undefined.

The spec goes on to provide further conditions, but, generally
speaking, But, roughly speaking, arg's type was Base[T], and T is a
type parameter of an enclosing method, so T' is Base[_], and Derived
can be typed as Base[_].

Piotr Kołaczkowski

unread,
May 21, 2011, 3:16:50 AM5/21/11
to scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org
Thank you for the explanation and the nice solution ;)

Best regards,
Piotr


W dniu 2011-05-20 23:11, Daniel Sobral pisze:

Piotr Kołaczkowski

unread,
May 21, 2011, 3:17:02 AM5/21/11
to scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org
Thank you for the explanation ;)

Best regards,
Piotr


W dniu 2011-05-20 23:11, Daniel Sobral pisze:

Piotr Kołaczkowski

unread,
May 21, 2011, 3:27:52 AM5/21/11
to scala...@googlegroups.com, Piotr Kołaczkowski, public-scala-user-/J...@lo.gmane.org, Piotr Kołaczkowski, public-public-scala-user-/JYPxA39Uh...@lo.gmane.org
Ok, so once again, I try to be more clear. Forget the previous code.

trait C[T]
case class CC1[T](value: T)
case class CC2[T](value: C[T])

class Test[T] {
def method(arg: Any) {
arg match {

case CC1(x: T) => // ok
case CC2(x: C[T]) => // error
}
}
}


<console>:15: error: pattern type is incompatible with expected type;
found : C[T]
required: C[Any]
Note: T <: Any, but trait C is invariant in type T.


You may wish to define T as +T instead. (SLS 4.5)

case CC2(x: C[T]) => // error


Questions:
1. Where it got that C[Any] from and why?
2. Why it doesn't complain on the first pattern in the same way - why
not an error "found T, required Any"?

Best regards,
Piotr


W dniu 2011-05-20 17:58, Paul Phillips pisze:

Tony Morris

unread,
May 21, 2011, 3:33:44 AM5/21/11
to scala...@googlegroups.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 21/05/11 07:11, Daniel Sobral wrote:
> Should the compiler compile this, or should it complain that match is
> impossible? This could be argued either way, but the benefit of static
> typing is that the compiler can complain, so the bias here is to
> complain whenever possible.

The answer cannot be argued either way. The answer is equivalent to
the answer to this question: Is Scala a total language?

The answer to this question (and therefore both questions) is no. We
can also replace the word "should" with "can." It's not possible to
complain about exhaustive patterns in a non-total language such as Scala.

Try it. Upon failure, blame the universe.

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk3XatcACgkQmnpgrYe6r61ZwQCgkAH9e1vufgOE4LJagKBa+WV6
1YEAn1CdLaihUmvIuyGKsz2EyIxo5YXk
=1k7I
-----END PGP SIGNATURE-----

Daniel Sobral

unread,
May 21, 2011, 11:33:19 AM5/21/11
to tmo...@tmorris.net, scala...@googlegroups.com
On Sat, May 21, 2011 at 04:33, Tony Morris <tonym...@gmail.com> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 21/05/11 07:11, Daniel Sobral wrote:
>> Should the compiler compile this, or should it complain that match is
>> impossible? This could be argued either way, but the benefit of static
>> typing is that the compiler can complain, so the bias here is to
>> complain whenever possible.

> The answer cannot be argued either way. The answer is equivalent to
> the answer to this question: Is Scala a total language?

No, Tony, it plainly is not. The answer is equivalent to the answer to
*this* question: should the compiler complain about 5 == "abc"?

> The answer to this question (and therefore both questions) is no. We
> can also replace the word "should" with "can." It's not possible to
> complain about exhaustive patterns in a non-total language such as Scala.

First, no one said anything about exhaustive patterns. I know you want
to help, but discussing the taste of apples while we talk about the
smell of roses doesn't help anyone. Second, just because it is not
possible for the compiler to do so in *all* cases doesn't mean it is
not possible for the compiler to do so in some cases.

Paul Phillips

unread,
May 21, 2011, 5:34:41 PM5/21/11
to Piotr Kołaczkowski, scala-user
On 5/21/11 12:27 AM, Piotr Kołaczkowski wrote:
> trait C[T]
> case class CC1[T](value: T)
> case class CC2[T](value: C[T])
>
> class Test[T] {
> def method(arg: Any) {
> arg match {
> case CC1(x: T) => // ok
> case CC2(x: C[T]) => // error
> }
> }
> }
>
>
> <console>:15: error: pattern type is incompatible with expected type;
> found : C[T]
> required: C[Any]
> Note: T <: Any, but trait C is invariant in type T.
> You may wish to define T as +T instead. (SLS 4.5)
> case CC2(x: C[T]) => // error
>
>
> Questions:
> 1. Where it got that C[Any] from and why?
> 2. Why it doesn't complain on the first pattern in the same way - why
> not an error "found T, required Any"?

Can you reformulate these questions in terms of section 8.3 of the
specification? It's called "Type Parameter Inference in Patterns". The
questions I can attempt to answer (emphasis on attempt) are the ones
approximately of the form "the following excerpt from the specification
implies <something> so why does <something>..."

Reply all
Reply to author
Forward
0 new messages