Why does this flatMap fail?

scala

Solution

Not really the precise answer, but two observations - Scala 2.10 will give you a nicer error:

scala> s.flatMap(_.getEnumConstants)
<console>:9: error: no type parameters for method flatMap: (f: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Class[_ <: Enum[_]]],B,That])That exist so that it can be applied to arguments (Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] })
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] }
 required: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[?B]
              s.flatMap(_.getEnumConstants)
                ^
<console>:9: error: type mismatch;
 found   : Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] }
 required: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[B]
              s.flatMap(_.getEnumConstants)
                          ^
<console>:9: error: Cannot construct a collection of type That with elements of type B based on a collection of type Seq[Class[_ <: Enum[_]]].
              s.flatMap(_.getEnumConstants)
                   ^

And, if you split your `flatMap`, you get to see a simpler version of the issue:

scala> s.map(_.getEnumConstants)
res28: Seq[Array[_$1 with Object] forSome { type _$1 <: Enum[_] }] = List(Array(NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS), Array(RELEASE_0, RELEASE_1, RELEASE_2, RELEASE_3, RELEASE_4, RELEASE_5, RELEASE_6))
scala> res28.flatten
<console>:10: error: No implicit view available from Array[_$1 with Object] forSome { type _$1 <: Enum[_] } => scala.collection.GenTraversableOnce[B].
              res28.flatten
                    ^

That is rather surprising since you'd think that it should be easy to turn an `Array` into a `GenTraversableOnce`. I don't have time to dig out the details at the moment, but I'll point out that the following things seem to work:

s.flatMap(_.getEnumConstants.toSeq)
s.flatMap(_.getEnumConstants.map(_.asInstanceOf[Enum[_]]))

I vote compiler bug, because of this gist, which shows some very weird behaviour in the REPL for this simple script

val s: Seq[Class[_ <: java.lang.Enum[_]]] = Seq(classOf[java.util.concurrent.TimeUnit], classOf[javax.lang.model.SourceVersion])
s.flatMap(_.getEnumConstants.toSeq)
s.flatMap(_.getEnumConstants.toArray)
1234

Problem

``` scala> val s: Seq[Class[_ <: java.lang.Enum[_]]] = Seq(classOf[java.util.concurrent.TimeUnit]) s: Seq[Class[_ <: java.lang.Enum[_]]] = List(class java.util.concurrent.TimeUnit) scala> s.flatMap(_.getEnumConstants) <console>:9: error: no type parameters for method flatMap: (f: Class[_ <: java.lang.Enum[_]] => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Class[_ <: java.lang.Enum[_]]],B,That])That exist so that it can be applied to arguments (Class[_ <: java.lang.Enum[_]] => scala.collection.mutable.ArrayOps[_$1(in value $anonfun) with java.lang.Object] forSome { type _$1(in value $anonfun) <: java.lang.Enum[_] }) --- because --- argument expression's type is not compatible with formal parameter type; found : Class[_ <: java.lang.Enum[_]] => scala.collection.mutable.ArrayOps[_$1(in value $anonfun) with java.lang.Object] forSome { type _$1(in value $anonfun) <: java.lang.Enum[_] } required: Class[_ <: java.lang.Enum[_]] => scala.collection.GenTr... s.flatMap(_.getEnumConstants) ```

Original source