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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With