Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flatMap behavior changed in 2.10.0

I was converting some code from 2.9 to 2.10 and came across an unexpected compilation error. Here's the minimal form:

In 2.9.2, this works fine:

scala> List(1).flatMap(n => Set(1).collect { case w => w })
res0: List[Int] = List(1)

In 2.10.0, we get an error:

scala> List(1).flatMap(n => Set(1).collect { case w => w })
<console>:8: error: no type parameters for method flatMap: (f: Int => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[List[Int],B,That])That exist so that it can be applied to arguments (Int => scala.collection.immutable.Set[_ <: Int])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Int => scala.collection.immutable.Set[_ <: Int]
 required: Int => scala.collection.GenTraversableOnce[?B]
              List(1).flatMap(n => Set(1).collect { case w => w })
                      ^
<console>:8: error: type mismatch;
 found   : Int => scala.collection.immutable.Set[_ <: Int]
 required: Int => scala.collection.GenTraversableOnce[B]
              List(1).flatMap(n => Set(1).collect { case w => w })
                                ^
<console>:8: error: Cannot construct a collection of type That with elements of type B based on a collection of type List[Int].
              List(1).flatMap(n => Set(1).collect { case w => w })
                             ^

But it works fine in 2.10.0 if I explicitly turn the inner result into a List or specify the generic types of flatmap explicitly:

scala> List(1).flatMap(n => Set(1).collect { case w => w }.toList)
res1: List[Int] = List(1)
scala> List(1).flatMap[Int, List[Int]](n => Set(1).collect { case w => w })
res2: List[Int] = List(1)

Can someone explain to me what the change was to 2.10 that causes the type inference to fail here when it didn't in 2.9?

EDIT:

Digging a little deeper, we can see that the issue arises from a difference in the behavior of collect:

In 2.9.2:

scala> Set(1).collect { case w => w }
res1: scala.collection.immutable.Set[Int] = Set(1)

In 2.10.0:

scala> Set(1).collect { case w => w }
res4: scala.collection.immutable.Set[_ <: Int] = Set(1)

Presumably the reason has to do with the fact that Set, unlike, for example List, is type invariant. But a more complete explanation, and especially one that gives the motivation for this change, would be great.

like image 375
dhg Avatar asked Jan 05 '13 17:01

dhg


Video Answer


1 Answers

It's a bug. You can also work around it by typing the pattern, as in

scala> Set(1).collect { case w => w }
res0: scala.collection.immutable.Set[_ <: Int] = Set(1)

scala> Set(1).collect { case w: Int => w }
res1: scala.collection.immutable.Set[Int] = Set(1)
like image 179
psp Avatar answered Nov 13 '22 11:11

psp