scala Map filterKeys: Projection cannot be assigned to a Map reference
-
09-09-2019 - |
Question
The following code:
var m: Map[String, Int] = Map("A" -> 1, "BB" -> 2, "CCC" -> 3)
m = m filterKeys { s => s.length < 3 }
Does not compile. I get the following error:
error: type mismatch
found: collection.this.Map.Projection[scala.this.Predef.String,scala.this.Int]
required: collection.this.Map[scala.this.Predef.String,scala.this.Int]
m = m filterKeys { s => s.length < 3 }
I don't really understand this as according to the scaladoc a Projection[A,B]
extends the trait Map[A,B+]
. That is, a Projection is a Map.
I thought it might be something to do with the contravariant type B
but if I use Any
instead of Int
, it still doesn't compile. What am I missing? The solution is to do:
var m: Map[String, Int] = Map("A" -> 1, "BB" -> 2, "CCC" -> 3)
m = Map(m filterKeys { s => s.length < 3 } toSeq : _ *)
but this seems inelegant to me.
Solution
OK - this has been figured out with the help of the scala console:
scala> var m = Map("A" -> 1, "BB" -> 2, "CCC" -> 3)
m: scala.collection.immutable.Map[java.lang.String,Int] = Map(A -> 1, BB -> 2, CCC -> 3)
So the type inference is inferring m's type as being an immutable map. The following code will compile OK:
var m: collection.Map[String, Int] = Map("A" -> 1, "BB" -> 2, "CCC" -> 3)
m = m filterKeys { s => s.length < 3 }
However, this is not much help as the map can not be added to in such a way as to return a collection.Map
. I think that they should have overridden the ++
method inherited from Iterable
with Map
as the return type.
Could anyone comment on this? What use a collection.Map
?
OTHER TIPS
I'm curious why you want m to be var rather than val - if you're not trying to reassign the Map to itself, things seem to work OK, as shown in the repl, and this is more in keeping with the scala philosophy of preferring immutability where possible:
scala> val m = Map("A" -> 1, "BB" -> 2, "CCC" -> 3)
m: scala.collection.immutable.Map[java.lang.String,Int] = Map((A,1), (BB,2), (CCC,3))
scala> val n = m filterKeys { s => s.length < 3 }
n: scala.collection.immutable.Map[java.lang.String,Int] = Map((A,1), (BB,2))
I see that the question is kind of old, it's possible that the behaviour you're seeing is different in Scala 2.8 given the major refactoring of the collections classes.