Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this flatMap fail?

Tags:

scala

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)
like image 881
Ryan LeCompte Avatar asked Mar 12 '13 06:03

Ryan LeCompte


People also ask

Why do we need flatMap?

We can use a flatMap() method on a stream with the mapper function List::stream. On executing the stream terminal operation, each element of flatMap() provides a separate stream. In the final phase, the flatMap() method transforms all the streams into a new stream.

What does flatMap return?

The flatMap() method returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.

What is flatMap in Scala?

flatMap() method is method of TraversableLike trait, it takes a predicate, applies it to each element of the collection and returns a new collection of elements returned by the predicate.

Does flatMap preserve order?

Does flatmap() method preserve the order of the streams? Yes, It does and map() also.


2 Answers

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
like image 106
themel Avatar answered Oct 21 '22 18:10

themel


TimeUnit.getEnumConstants returns a java array TimeUnit[], while flatMap expects a GenTraversable

You can get by with

scala> s.flatMap(_.getEnumConstants.toSeq)
res4: Seq[Enum[_]] = List(NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS)
like image 28
pagoda_5b Avatar answered Oct 21 '22 18:10

pagoda_5b