Reputation: 613
This is a follow-up on the question Scala implicit typeclass precedence in companion objects.
Suppose that I have two traits, Trait2 extends Trait1
. Each trait has a specific typeclass instance of Eq
. I'd like to let the precedence of the typeclass instance of Trait2
to be higher than tha of Trait1
. However, the code below (the LowPriorityImplicits
trick) does not work.
trait Eq[-A] {
def eq(a: A, b: A): Boolean
}
object Eq {
implicit object IntEq extends Eq[Int] {
def eq(a: Int, b: Int) = a == b
}
}
trait Trait1[+A]
trait Trait2[+A] extends Trait1[A]
object Implicits extends LowPriorityImplicits {
implicit def Eq2[T: Eq]: Eq[Trait2[T]] = ???
}
trait LowPriorityImplicits {
implicit def Eq1[T: Eq]: Eq[Trait1[T]] = ???
}
object Test2 extends App {
def f[T: Eq](x: T) = ???
import Implicits._
val t1 = new Trait1[Int] {}
val t2 = new Trait2[Int] {}
f(t2) // COMPILATION ERROR!
}
The following compilation error is thrown:
Error:(33, 4) ambiguous implicit values:
both method Eq1 in trait LowPriorityImplicits of type [T](implicit evidence$2: Eq[T])Eq[Trait1[T]]
and method Eq2 in object Implicits of type [T](implicit evidence$1: Eq[T])Eq[Trait2[T]]
match expected type Eq[Trait2[Int]]
f(t2)
^
How can I enforce the precedence relation of the typeclass instances?
Upvotes: 4
Views: 279
Reputation: 41
Variance in type parameters doesn't play well with Scala's encoding of type classes. If you want it to compile, simply try this.
trait Eq[A] {
def eq(a: A, b: A): Boolean
}
object Eq {
implicit object IntEq extends Eq[Int] {
def eq(a: Int, b: Int) = a == b
}
}
trait Trait1[A]
trait Trait2[A] extends Trait1[A]
object Implicits extends LowPriorityImplicits {
implicit def Eq2[T: Eq]: Eq[Trait2[T]] = ???
}
trait LowPriorityImplicits {
implicit def Eq1[T: Eq]: Eq[Trait1[T]] = ???
}
object Test2 extends App {
def f[T: Eq](x: T) = ???
import Implicits._
val t1 = new Trait1[Int] {}
val t2 = new Trait2[Int] {}
f(t2) // COMPILATION ERROR!
}
If you do want Eq[Trait2[A]]
to behave like a sub-type of Eq[Trait1[A]]
, you might be able to use implicit conversions as a workaround.
Upvotes: 1