Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

match for types failed on Map

Tags:

scala

I'm learning Scala and trying to write some simple code.

When I tried to write a method like this:

def func(value: Any) {
  value match {
    case i: Int => println(1)
    case vector: Vector[Any] => println(2)
    case map: Map[Any, Any] => println(3)
    case _ => println(4)
  }
}

I got an warn:

[warn]........:31: non-variable type argument Any in type pattern scala.collection.immutable.Map[Any,Any] (the underlying of Map[Any,Any]) is unchecked since it is eliminated by erasure
[warn]       case map: Map[Any, Any] => println(3)
[warn]                    ^
[warn] one warning found

I am wondering why using Map[Any, Any] will get this warn but Vector[Any] will not.

like image 428
Hwaipy Li Avatar asked Mar 14 '23 11:03

Hwaipy Li


2 Answers

The problem is that a Map[X, Y] is not covariant in its type parameter X (but a Vector[X] is).

What does that mean? Suppose B <: A (read, B is a subtype of A).

Then we have Vector[B] <: Vector[A]. That makes sense: If we retrieve an element x from a Vector[B], it will be a B. That means it is also an A by the subtyping relationship. (A similar argument applies to all other methods.)

Following similar reasoning, Map[X, B] <: Map[X, A] for all X (element retrieval is by key and not index, but essentials remain the same).

However, this doesn't hold for Map's first type parameter. Assume that Map[B, X] <: Map[A, X] for some X.

We could now do the following:

val x: Map[B, X] = ???
x.get(b: B) // makes sense

val y: Map[A, X] = x // must be ok, Map[B, X] <: Map[A, X]
y.get(a: A) // bad! x doesn't know how to "get" with something of type `A`

Therefore, a Map[_, _] is not necessarily a Map[Any, Any]. To fix the error message, use:

case map: Map[_, _] => ...
like image 23
gzm0 Avatar answered Mar 24 '23 18:03

gzm0


The reason is that Map is invariant in its first type parameter. This means that not any map is a sub-type of Map[Any,Any]. On the contrary, Vector is covariant in its type parameter, so any Vector is always a sub-type of Vector[Any], which means that the compiler does not need to check if the actual runtime type is Vector[Any] (which it cannot do anyway due to erasure) as even if it is say a Vector[String] it is safe to trat it as a Vector[Any].

like image 90
Régis Jean-Gilles Avatar answered Mar 24 '23 16:03

Régis Jean-Gilles