Map.getOrElseUpdate should use value

Hi there!

First time here so sorry if I’m doing something wrong. I did my homework and I don’t see a solution for this problem anywhere, and I feel that it might be a nice feature to have.

Currently (Scala 2.12), HashMaps use an underlying HashTable that can access the entry where a value is stored (final class DefaultEntry[A, B](val key: A, var value: B)), but modification of this entry from outside is blocked.

My use case is that I want to mutate a value, say increment a count per key. I find it inefficient to do map.put(map.getOrElse(key, 0) + 1) since it forces me to find the entry two times and looks convoluted.

I was thinking of combining withDefaultValue(0) with map.getOrElseUpdate(key, <updated value>) but alas, I can’t use the old value to generate the new one, just provide a new value.

Hence, my 2 cents would be if a new overload can be created that looks like this:
override def getOrElseUpdate(key: A, update: B => B): B and provides the old value in order to update the old one. In the counter example, it would be used as map.getOrElseUpdate(key, old => old + 1).

The same could apply to the update method. Or, if we don’t want to force use of withDefaultValue(), perhaps something like map.transformValue(key: A, transformation: Option[B] => B) ?

2 Likes

Have you looked at the current release? It brings lots of collection improvements. And I believe it has exactly what you need:
def updateWith(key: K)(remappingFunction: (Option[V]) => Option[V]): Option[V]

It is especially nice on the TrieMap since it allows thread safe updates.

As a side note, 2.13 collections have become so feature rich, that I find it difficult to name any feature that is missing (except for, maybe, BitSet shifts and TreeMap range counts).

5 Likes

Hi linasm. Thanks for the reply, indeed, it seems that is the solution. My bad, did most of my research on the 2.12 code and did not look deep into 2.13! I’ll need to start migrating ASAP now that it’s out…