Question

I have a function that I can't get type inference to work on. Full sample code is below, but the function in question is this:

def mapObjects[T, S <: HasGetter[T]](lst: GenSeq[S]): GenSeq[T] = {
  lst map {v => v.getT}
}

The problem is that calling mapObjects requires naming types T and S explicitly. Is there a way to write this function's type signature so that inference works correctly?

Working sample code:

import scala.collection.GenSeq

trait HasGetter[T] {
  def getT: T
}

class HasStringGetter(str: String) extends HasGetter[String] {
  override def getT = str
}

object TypeInferenceTest {
  def mapObjects[T, S <: HasGetter[T]](lst: GenSeq[S]): GenSeq[T] = {
    lst map {v => v.getT}
  }

  def tst {
    val objs = List(new HasStringGetter("abc"), new HasStringGetter("def"), new HasStringGetter("hij"))

    // Doesn't typecheck
    // val strs = mapObjects(objs)

    val strs = mapObjects[String, HasStringGetter](objs)
  }
}
Was it helpful?

Solution

How about just:

def mapObjects[T](lst: GenSeq[HasGetter[T]]): GenSeq[T] = {
    lst map {v => v.getT}
  }

scala> mapObjects(objs)
res18: scala.collection.GenSeq[String] = List(abc, def, hij)

There is no real advantage of using S <: HasGetter[T] in your case as you are just doing a map over lst and obtaining elements of type T. And your return type of the function has got nothing to with type S. Hence there is no need to get the precise type S

Had the return type of the function or function body explicitly needed to maintain the type S <: HasGetter[T], your code would be needed. But in this case there is no point maintaining the type.

Moreover GenSeq[+A] is a covariant type. So by default it can accept types belonging to GenSeq[ <: HasGetter[_]] in the argument. Has GenSeq not been co-variant, it would have been a different Issue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top