3
votes

Frequently, I find myself implementing methods that build a map from an input source. In this case, I use a scala.collection.mutable.Map, assuming greater speed and efficiency; however, once this collection is built, I no longer want it to be mutable.

What is the preferred Scala way of returning an immutable map from a mutable one? Usually, I do a myMap.toMap which obviously works, but smells. Alternatively, you can set the return type to scala.collection.Map which doesn't require building a new collection, but seems like it could confuse readers.

Thanks for any replies.

3
I think using a newBuilder as in this other question and then .result would be an equivalent solution with some style merits over defining a mutable Mapmatanster

3 Answers

7
votes

The best way is to call .toMap. It's short, clean, and is an explicit way of saying that you want to convert your collection to an immutable.Map.

I think setting the type to scala.collection.Map would, indeed, be confusing. It also wouldn't protect you from someone setting the type back. Making the type immutable.Map is clear and safe.

5
votes

I'm not sure why you think .toMap smells, but if you want to be explicit collection.immutable.Map() ++ myMap ought to clearly document what is going on. (Don't forget the (); they're not optional.)

Simply changing the return type doesn't fully fix the immutability problem; the mutating methods are no longer visible, but the user could easily cast back. That is the highest performance approach, though, since nothing is really changing.

0
votes
import scala.collection._
import scala.collection.JavaConversions._

val myMap: mutable.Map[K,V] = ???
val unmodifiable: mutable.Map[K,V] =
  java.util.Collections.unmodifiableMap[K,V](myMap)
val newMap = unmodifiable.asInstanceOf[scala.collection.Map[K,V]]

You can cast newMap to a mutable.Map, but modifications will throw UnsupportedOperationException.

In my case, the maps may be small enough that toMap may be faster and use less memory.