DEV Community

Adam Cervenka
Adam Cervenka

Posted on

Scala Tip: mapValues may not do what you expect

Often in Scala you may need to map over values of Map data structure. You can use the usual map function, but there is also more concise mapValues:

Map("a" -> 2).map{ case (k,v) => k -> (v + 2) }

Map("a" -> 2).mapValues(_ + 2)
Enter fullscreen mode Exit fullscreen mode

In many situations the result of these two will be identical, but there is one important difference.

mapValues doesn't apply the provided function on the value right away. Instead, it creates a view (wrapper) over the data and only evaluates the function when the value is accessed.

This is OK if your code doesn't have any side effects, but if it has, it may cause hard to find issues. For example leaking of exceptions:

scala.util.Try(
  Map("a" -> 2).mapValues(v => (throw new RuntimeException))
).isSuccess
// returns true
Enter fullscreen mode Exit fullscreen mode

The newly created map will happily leave the Try wrapper as success, and the exception will be thrown only when the value is accessed later.

In my opinion, mapValues name was a poor choice because it seems to suggest the same functionality as map, but only for values. Maybe wrapValues would be better?

If you want to be more concise, but still have the same semantics as a map function, you can use transform:

Map("a" -> 2).transform((k,v) => v + 2)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)