views:

333

answers:

3

Why can't I add to a scala.collection.Map? It seems that this trait is pretty useless without this functionality.

Couldn't they have overridden the ++ method in Iterable and reduced the return type to a Map?

P.S. I don't mean that it should be mutable, just that it should be able to return a new Map with an added mapping (or mappings), the same as an immutable.Map.

A: 

My guess is: If you have some collection and need to provide a read only Map facade for others, this trait is suitable for the job as is. If you include addition there it would not be orthogonal design since one would need then read-only map interface then. On the other hand if ++ operation in generic interface is required it would not be suitable for both mutable and immutable implementations. E.g. if mutable collection returned self on addition it would not be obvious what happens just by looking at interface.

Petr Gladkikh
But the immutable Map *does* define a ++ operator! That's my point! It returns a (new) map with the mapping added. If using scala.collection.Map is implicitly an immutable Map, I don't see why it can't have the functionality of one. After all, they are hardly going to change the Predef are they?
oxbow_lakes
Indeed, as David Hall pointed out my guess might not hold. scala.collections.Map inherits from scala.collections.generic.MapTemplate that provides "++" (immutable) operation.See however deprecation annotations on ++ methods in MutableMapTemplate (that is inherited by scala.collections.mutable.Map)
Petr Gladkikh
(I looked at 2.8 svn trunk sources)
Petr Gladkikh
+1  A: 

The Scala collections library is currently fairly flawed. 2.8 (due for release in a month or so) has a completely revamped collections library that I believe has the behavior you're looking for.

+2  A: 

I'll leave the original answer below, though it is pretty much incorrect, as I didn't understand the question correctly.

Scala's present collection library pretty much enforces different adding methods for mutable/immutable, probably in the hope of making clear in the source code what type of collection is being used. As said, this is being revised in 2.8, and that premise is going away.

That being the case, the abstract classes do not provide the methods you are thinking of, because they might exist for immutable but not for mutable, and vice versa. Or they might have the same name, but different implementations.

And, therefore, it would be impossible to provide them in the base class.

But, furthermore, notice that, this way, if you receive a scala.collection.map, you cannot screw it up by treating it as mutable when you received an immutable, or vice versa.

And, now, for the wrong answer. :)

You can (no, you can't -- the code below uses scala.collection.imutable.Map).

scala> val x = Map(1 -> 'a', 2 -> 'b')
x: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b)

scala> x ++ Map(3 -> 'c')
res5: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b, 3 -> c)

scala> var y = x
y: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b)

scala> y += (3 -> 'c')

scala> y
res7: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b, 3 -> c)

scala> x + (3 -> 'c')
res8: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b, 3 -> c)
Daniel
Hmmmm. It seems to me that by creating two types both called Map, both extending collections.Map but behaving completely differently, the Scala library creators have already created the situation in which I can "screw up by treating [something] as mutable when [it is] immutable". If they didn't want this to be the case, they shouldn't have a shared supertype!
oxbow_lakes
They are both maps in the sense that they are both collections which can be accessed by keys. That's a map. And, as you yourself found out, the classes were written so you wouldn't screw yourself up.
Daniel