1
votes

I'm upgrading a software scala based from scala 2.12 to scala 2.13. Some blocks of code was broken and fixing them I found a wierd behavior in an already existing code.

@Edit

Below we have an explanation of a use case of this problem.

The problem in general is the usage of the method .map in mutable or immutable maps since Scala 2.13. At the end of the question we have an easy way to reproduce, and further we have the answer.

Obs.:

  • The term variables used there is a business field, its not related to scala (or java) variables.

    list is an Array[Long] containing idProject.

    The return of p.getVariables is a Map[String, VariableSet].

    So after the second .map (line 4), we have an Array[(Project, Map[String, VariableSet])]

The code is:

// get the projects
    list.map(projectById)
      // and map their variable
      .map(p => p -> p.getVariables)
      // and transform them to DTOs
      .map(pair => pair._2.map(set => toVariableDTO(set._2, pair._1.getId)).toArray)
      // and return the union of all of them
      .reduce((l, r) => l.union(r))
      // and sort them by name
      .sortBy(_.name.toLowerCase)

The problems comes at the 6th line, because after the upgrade it recognizes the set (pair._2.map(set => ) as type "Nothing" .

I tried line by line and it seems to work.

Like this:

val abs = list.map(projectById).map(p => p -> p.getVariables)
    val ab = abs.map(pair => pair._2)
    ab.map(pair => pair)

The problem here is that in the 6th line of previous example I need the reference to the project associated to that flow.

Of course, there would be room to rewrite this in another way (continuing the work on the second example), but I have many many other cases like this and would like to know if its really supposed not to work anymore of if I miss something during the upgrade.

Thanks in advance!

@Edit

Easy way to reproduce:

import scala.collection.mutable.{Map => MMap}

val mmap: MMap[String, Long] = MMap[String, Long]()

mmap.map(set => ) // Here, it recognizes 'set' as Nothing .

Looks like scala 2.13 see an element of Mutable Map as 'Nothing' ?

1
As a quick advice - try working out a minimal example. I'd take a look if I could compile it in 3sec, but I don't have time to set up all the dummy variables, not to mention things like toVariableDTO .slouc
Why use 3 map calls rather than one?Tim
@slouc added an easy way to reproduce.Fernando Rezk
@Fernando Great! I also see that you already found the main cause of the problem. In general, these kinds of examples not only make it easier for others to take a look at your problem and see if they can figure it out, but it also might help you figure it out yourself by stripping off the unnecessary parts. Cheers!slouc

1 Answers

3
votes

Well, after searching and struggling for hours, I figure out that this is one of the major changes in scala 2.13.

To use the expected behavior from the .map method, executed in map objects, we need to explicitly say that it should use the implementation from Iterable (which is the default on in scala 2.12 or lower). We do that adding a .iterator before the .map call.

So for that, according to my "easy to reproduce" step would be like that:

import scala.collection.mutable.{Map => MMap}

val mmap: MMap[String, Long] = MMap[String, Long]()

mmap.iterator.map(set => set._2) // Now we may use the 'set' normally

I will make a few changes in my question to make it easier to find, for those who may have a similar problem.