My present use case is pretty trivial, either mutable or immutable Map will do the trick.
Have a method that takes an immutable Map, which then calls a 3rd party API method that takes an immutable Map as well
def doFoo(foo: String = "default", params: Map[String, Any] = Map()) {
val newMap =
if(someCondition) params + ("foo" -> foo) else params
api.doSomething(newMap)
}
The Map in question will generally be quite small, at most there might be an embedded List of case class instances, a few thousand entries max. So, again, assume little impact in going immutable in this case (i.e. having essentially 2 instances of the Map via the newMap val copy).
Still, it nags me a bit, copying the map just to get a new map with a few k->v entries tacked onto it.
I could go mutable and params.put("bar", bar)
, etc. for the entries I want to tack on, and then params.toMap
to convert to immutable for the api call, that is an option. but then I have to import and pass around mutable maps, which is a bit of hassle compared to going with Scala's default immutable Map.
So, what are the general guidelines for when it is justified/good practice to use mutable Map over immutable Maps?
Thanks
EDIT so, it appears that an add operation on an immutable map takes near constant time, confirming @dhg's and @Nicolas's assertion that a full copy is not made, which solves the problem for the concrete case presented.
Depending on the immutable Map implementation, adding a few entries may not actually copy the entire original Map. This is one of the advantages to the immutable data structure approach: Scala will try to get away with copying as little as possible.
This kind of behavior is easiest to see with a List
. If I have a val a = List(1,2,3)
, then that list is stored in memory. However, if I prepend an additional element like val b = 0 :: a
, I do get a new 4-element List
back, but Scala did not copy the orignal list a
. Instead, we just created one new link, called it b
, and gave it a pointer to the existing List a
.
You can envision strategies like this for other kinds of collections as well. For example, if I add one element to a Map
, the collection could simply wrap the existing map, falling back to it when needed, all while providing an API as if it were a single Map
.