Reputation: 73
I want to extends a class with a val of mutable.HashMap[] like this:
class Father
class Son extends Father
class C1{
val m = new mutable.HashMap[Int, Father]()
}
class C2 extends C1{
override val m = new mutable.HashMap[Int, Son]()
}
And get an error:
Error:(19, 16) overriding value m in class C1 of type scala.collection.mutable.HashMap[Int,ScalaByExample.Father]; value m has incompatible type override val m = new mutable.HashMapInt, Son
I found that immutable.HashMap
is covariant but mutable.HashMap
is invariant. It works if replace mutable.HashMap
with immutable.HashMap
.
So my two questions are:
How can I make it works using mutable.HashMap?
Why did scala's author design HashMap like this?
Upvotes: 5
Views: 427
Reputation: 953
The reason that immutable collections in Scala are able to be covariant is because if you want to add an element, you will actually be creating a brand new object, with a (potentially) different underlying type. That's to say the underlying type of the new map will be either the same type as in the original or a supertype, as required.
So, in your situation, if you start with an instance of HashMap[Int,Son] and add an object which is a Father, the resulting map will actually be of type HashMap[Int,Father]. All but one of the elements of the new map will actually be Son objects (Son is a subclass of Father). Only the one that you added will actually be a Father. But as far as the compiler is concerned, all it knows about the new map is that all elements are of type Father.
If, as I imagine, the types of your maps are more important to you than the mutability, then you should switch to immutable types. It's rare that you really need mutability in a collection like this.
Upvotes: 1
Reputation: 370162
Mutable maps are invariant because writing to them wouldn't be safe otherwise. Consider for example the following function:
def f(o: C1) {
o.m(42) = new Father
}
This method is perfectly well-typed. But if you passed in an instance of C2
as the value for o
, it'd break because a Map[Int, Son]
is not allowed to contain Father
objects. Therefore your definition of C2
is ill-typed.
Upvotes: 6