Is it possible to resolve an implicit parameter for a type B if an implicit is defined for its super type A?
Here is an example :
I have an Enumerable typeclass :
trait Enumerable[A] {
def name(a: A): String
def list: List[A]
//... other methods
}
object Enumeration {
def name[A, T >: A](a: A)(implicit ev: Enumerable[T]) = ev.name(a)
def list[T](implicit ev: Enumerable[T]) = ev.list
// ...
}
Then I define an instance of enumerable :
sealed trait Season
case object Winter extends Season
case object Spring extends Season
case object Summer extends Season
case object Fall extends Season
implicit val seasonEnumerable = new Enumerable[Season] {
override def list: List[Season] = List(Winter, Spring, Summer, Fall)
}
// working :
Enumeration.name(Winter: Season) shouldBe "winter"
// faling :
Enumeration.name(Winter) shouldBe "winter"
Enumeration.name(Winter) is failing if I don't tell scalac that Winter is a Season. I've specified that the implicit parameter in the 'name' method signature is a supertype of A, but it's not sufficient...
Is there a better way to do this?
Eduardo's answer explains why the version with [A, T >: A]
doesn't work. But there is a simpler solution to the problem than he gives: instead of introducing T
infer as a type parameter, introduce it by an existential type:
def name[A](a: A)(implicit ev: Enumerable[T >: A] forSome { type T }) = ev.name(a)
Or, using a shorthand,
def name[A](a: A)(implicit ev: Enumerable[_ >: A]) = ev.name(a)
Then the compiler only has to decide what T
is when looking for ev
.