Reputation: 265
Take the following Scala code:
import scala.collection.mutable.HashMap
class father[T,K:Numeric] extends HashMap[T,K]
class sonA[T] extends father[T, Long]
class sonB[T] extends father[T, Double]
def func_sonA[T](x: List[T]) = {
// code
new sonA[T]
}
def func_sonB[T](x: List[T]) = {
// code
new sonB[T]
}
val strList = List("one", "two", "three", "four")
val intList = List(1,2,3,4)
val both:List[List[Any]] = List(strList, intList)
val mapped = both.map(x =>
x match {
case i:List[String] => func_sonA(i)
case i:List[Int] => func_sonB(i)
}
)
The type for mapped
is: List[father[_ >: String with Int, _ >: Long with Double : AnyVal]]
.
What exactly does _>:
means?
What's the idea behind String with Int
and what is it good for?
Seems that it can grow indefinitely (String with Int with Double With Long with...
).
How can I specify the type of mapped
to be just List[father]
or List[father[Any, Any]]
without losing the type information?
I'm having a bit of a difficulty finding answers since search results for phrases _>:
aren't very relevant.
EDIT:
To illustrate the actual problem its causing, I want to use a function with a List[father[Any, Any]]
input but I can't pass mapped
. I'm getting a type mismatch error.
Function:
def bar(x: List[father[Any, Any]]) = {
println(x)
}
bar(mapped)
Error:
Error:(52, 9) type mismatch;
found : List[father[_ >: String with Int, _ >: Long with Double <: AnyVal]]
required: List[father[Any,Any]]
bar(mapped)
^
Upvotes: 1
Views: 151
Reputation: 2173
_ >: String with Int
basically means, that the type is either String
OR Int
. In case of List[String]
you get back a sonA[String]
and therefore a father[String, Long]
, in case of List[Int]
respectively a sonB[Int]
and therefore a father[Int,Double]
so you end up with a father
where the first type is either String
or Int
and the second type is either Long
or Double
.
Regarding your other question:
How can I specify the type of mapped to be just
List[father]
orList[father[Any, Any]]
without losing the type information?
Why do you want that? The current type is actually more specific than just List[father]
or List[father[Any,Any]].
EDIT
Okay now I know what you want.
Basically what you want to achieve is that this becomes possible:
val mapped: List[father[Any,Any]] = both.map(x =>
x match {
case i:List[String] => func_sonA(i)
case i:List[Int] => func_sonB(i)
}
)
The problem here is, that currently with
class father[T,K] extends HashMap[T,K]
The scala compiler does not know that e.g. father[String,Long]
is supposed to be a subtype of father[Any,Any]
(this does not automatically result from String
and Long
being subtypes of Any
).
So, to tell Scala that the above should be applicable, you need the class father
to be covariant in both type parameters:
class father[+T,+K]
The problem with that is, that you are extending HashMap[T,K]
. But this class is only covariant in the first type Parameter T
, but not K
.
So this code here actually works, but it is not extending HashMap
:
class father[+T,+K]
class sonA[T] extends father[T, Long]
class sonB[T] extends father[T, Double]
def func_sonA[T](x: List[T]) = {
// code
new sonA[T]
}
def func_sonB[T](x: List[T]) = {
// code
new sonB[T]
}
val strList = List("one", "two", "three", "four")
val intList = List(1,2,3,4)
val both = List(strList, intList)
val mapped: List[father[Any,Any]] = both.map(x =>
x match {
case i:List[String] => func_sonA(i)
case i:List[Int] => func_sonB(i)
}
)
def bar(x: List[father[Any, Any]]) = {
println(x)
}
bar(mapped)
Further readings on covariance here.
Upvotes: 1