Call a method based on template type in Scala
generics, scala
Solution
You can use the same technique as the `CanBuildFrom` trait of collections.
We first create a `Getter` case class
case class Getter[T](getter: (ContentValues, String) => T) {
def getOpt(contentValues: ContentValues, key: String): Option[T] =
if (contentValues containsKey key) Some(getter(contentValues, key))
else None
}
This allows us to create a `ContentValues` wrapper that has the desired method.
implicit class ContentValuesWrapper(val c: ContentValues) extends AnyVal {
def getAsOpt[T](key: String)(implicit getter: Getter[T]) =
getter.getOpt(c, key)
}
Now, in order to call the `getAsOpt` method on `ContentValues` we need to provide `implicit` instances of `Getter` for the correct types.
object Getter {
implicit val intGetter = Getter(_ getAsInteger _)
implicit val longGetter = Getter(_ getAsLong _)
implicit val stringGetter = Getter(_ getAsString _)
}
Now you can use the `getAsOpt` method on a `ContentValues` instance.
// fake version of ContentValues
val c =
new ContentValues {
val m = Map("a" -> "1", "b" -> "2", "c" -> "3")
def getAsInteger(k: String): Int = getAsString(k).toInt
def getAsLong(k: String): Long = getAsString(k).toLong
def getAsString(k: String): String = m(k)
def containsKey(k: String): Boolean = m contains k
}
c.getAsOpt[Int]("a") //Option[Int] = Some(1)
c.getAsOpt[Long]("b") //Option[Long] = Some(2)
c.getAsOpt[String]("c") //Option[String] = Some(3)
c.getAsOpt[Int]("d") //Option[Int] = None
c.getAsOpt[Long]("e") //Option[Long] = None
c.getAsOpt[String]("f") //Option[String] = None
Problem
I'm trying to figure out a way to call a Java API from Scala. Basically, there's a `ContentValues` object that has a couple of methods like `getAsString`, `getAsLong`, each having their own different return type. Can I wrap `ContentValues` in another object so that I can add a `get[T]` method that calls the correct `getAsXXX` method depending on T? What I tried (didn't work, complains about ambiguous implicit resolution) : ``` object SContentValuesConversions { case class SContentGetter[ScalaType](val check: String => Boolean, val getter: String => ScalaType) { def getTyped(key: String): Option[ScalaType] = { if (!check(key)) None else Some(getter(key)) } } implicit def SIntContentValues(cv: ContentValues) = SContentGetter((cv containsKey _), (cv getAsInteger _)) implicit def SLongContentValues(cv: ContentValues) = SContentGetter((cv containsKey _), (cv getAsLong _)) implicit def SStringContentValues(cv: ContentValues) = SContentGetter((cv containsKey _), (cv getAsString _)) } ```