Scala: Why mapValues produces a view and is there any stable alternatives?

dictionary, scala

Solution

There's a ticket about this, SI-4776 (by YT).

The commit that introduces it has this to say:

Following a suggestion of jrudolph, made `filterKeys` and `mapValues` transform abstract maps, and duplicated functionality for immutable maps. Moved `transform` and `filterNot` from immutable to general maps. Review by phaller.

I have not been able to find the original suggestion by jrudolph, but I assume it was done to make `mapValues` more efficient. Give the question, that may come as a surprise, but `mapValues` is more efficient if you are not likely to iterate over the values more than once.

As a work-around, one can do `mapValues(...).view.force` to produce a new `Map`.

Problem

Just now I am surprised to learn that `mapValues` produces a view. The consequence is shown in the following example: ``` case class thing(id: Int) val rand = new java.util.Random val distribution = Map(thing(0) -> 0.5, thing(1) -> 0.5) val perturbed = distribution mapValues { _ + 0.1 * rand.nextGaussian } val sumProbs = perturbed.map{_._2}.sum val newDistribution = perturbed mapValues { _ / sumProbs } ``` The idea is that I have a distribution, which is perturbed with some randomness then I renormalize it. The code actually fails in its original intention: since `mapValues` produces a `view`, `_ + 0.1 * rand.nextGaussian` is always re-evaluated whenever `perturbed` is used. I am now doing something like `distribution map { case (s, p) => (s, p + 0.1 * rand.nextGaussian) }`, but that's just a little bit verbose. So the purpose of this question is: - Remind people who are unaware of this fact. - Look for reasons why they make `mapValues` output `view`s. - Whether there is an alternative method that produces concrete `Map`. - Are there any other commonly-used collection methods that have this trap. Thanks.

Original source