I'am trying to write something like this:
trait Typed[T]
trait Test {
def testMap: Map[Typed[_], Int]
def test = testMap.flatMap {case (typed, size) => Seq.fill(size)(typed)}
}
But I get the following error:
error: no type parameters for method flatMap: (f: ((Typed[_], Int)) => Traversable[B])(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Map[com.quarta.service.querybuilder.Typed[_],Int],B,That])That exist so that it can be applied to arguments (((Typed[_], Int)) => Seq[Typed[_0]] forSome { type _0 })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : ((Typed[_], Int)) => Seq[Typed[_0]] forSome { type _0 }
required: ((Typed[_], Int)) => Traversable[?B]
def test = testMap.flatMap {case (typed, size) => Seq.fill(size)(typed)}
This code works if change testMap type to:
def testMap: Map[Typed[Any], Int]
What is the difference and how I can solve my problem?
If I understood your question correctly, the answer is: You can do it if Typed
is covariant in T
, i.e. trait Typed[+T]
.
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Typed[+T: Manifest] {
override def toString = "Typed[" + implicitly[Manifest[T]].toString + "]"
}
trait Test {
def testMap: Map[Typed[_], Int]
def foo = testMap flatMap { case (t, s) => Seq.fill(s)(t) }
}
val bar = new Test {
def testMap = Map(new Typed[Double]() -> 3, new Typed[Int]() -> 5)
}
// Hit Ctrl-D
scala> bar.foo
res0: scala.collection.immutable.Iterable[Seq[Typed[Any]]] = List(Typed[Double], Typed[Double], Typed[Double], Typed[Int], Typed[Int], Typed[Int], Typed[Int], Typed[Int])
Note that I've made Typed
a class in this example to get nicer output. You can of course stick with a trait
.
Covariance basically means that if A <: B
then X[A] <: X[B]
. So if you were declaring testMap
as Map[Typed[Any], Int]
while Typed
were invariant, you were not allowed to pass in e.g. a Typed[Double]
for a Typed[Any]
even though Double <: Any
. Here, the scala compiler seems to be replacing _
with Any
in the covariant case (see extempore's comment for an elaboration on this).
For an explanation of the problem regarding the underscore, I'd refer to Luigi's answer though.
I think the problem is you're trying to pattern match an anonymous function with an existential type parameter.
From the language spec, section 8.5 regarding pattern matching anonymous functions:
The expected type of such an expression must in part be defined. It must be either
scala.Functionk[S1, ... , Sk, R]
for somek > 0
, orscala.PartialFunction[S1, R]
, where the argumenttype(s) S1, ... , Sk
must be fully determined, but the result typeR
may be undetermined.
testMap
is an existential type (see language spec 3.2.10). An existential type has the form T forSome {Q}
where Q is a sequence of type declarations. You have used the special placeholder syntax, so the type Map[Typed[_], Int]
is equivalent to Map[Typed[t] forSome { type t }, Int]
, which may make the error message make a bit more sense.
As for a solution, I guess it depends exactly what you're trying to do, which you don't say... :)
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