1

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)
        ^
4
  • I don't have a full answer, but this can help explain what >: means. Commented Aug 5, 2015 at 14:47
  • Edited my answer. Hope this clarifies it a bit. Commented Aug 6, 2015 at 15:18
  • So did it help you to solve your problem? Commented Aug 7, 2015 at 17:45
  • @thwiegan Not the answer I was hoping for but it does answer my question, thank you. Commented Aug 11, 2015 at 9:08

1 Answer 1

1

_ >: 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] or List[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.

Sign up to request clarification or add additional context in comments.

3 Comments

This simplified version has only String with Int, in general it could be anything and in my opinion Any would be more readable than String with Int with Double with .... Also I'd like to understand why it behaves like that so I can get a better understanding of the type system.
Scala always tries to find the lowest bounds for a type. In that case it is this construct. As long as you don't write it yourself, you won't need to read it and can just handle it as if it were father[Any,Any]. For further research you can read up on scala type inference.
Edited main post with a better reason to why I'd want it to be [Any, Any].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.