Skip to content

Instantly share code, notes, and snippets.

@retronym
Created December 3, 2010 06:52
Show Gist options
  • Save retronym/726662 to your computer and use it in GitHub Desktop.
Save retronym/726662 to your computer and use it in GitHub Desktop.
Workaround Scala's questionable Contravariant Implicit resolution rules
trait Inv[A] { self: Contra[A] => }
trait Contra[-A] extends Inv[A @uncheckedVariance]
implicit val C1: Contra[Any] = new Contra[Any] {}
implicit val C2: Contra[Int] = new Contra[Int] {}
assert(implicitly[Inv[Any]] eq C1)
assert(implicitly[Contra[Any]] eq C1)
assert(implicitly[Inv[Int]] eq C2)
assert(implicitly[Contra[Int]] eq C1)
import annotation.unchecked.uncheckedVariance
trait Inv[A] { self: Contra[A @uncheckedVariance] => }
trait Cov[+A] { self: Contra[A @uncheckedVariance] => val selff = self }
trait Contra[-A] extends Cov[A @uncheckedVariance] with Inv[A @uncheckedVariance]
case class Specific[A](a: Contra[A]) {
}
trait SpecificLow {
implicit def Contra[A](implicit ca: Contra[A]): Specific[A] = Specific(ca)
}
object Specific extends SpecificLow {
implicit def Cov[A](implicit ca: Cov[A]): Specific[A] = Specific(ca.selff)
}
implicit val CAny: Contra[Any] = new Contra[Any] {
override def toString = "Contra[Any]"
}
implicit val CInt: Contra[Int] = new Contra[Int] {
override def toString = "Contra[Int]"
}
assert(implicitly[Inv[Any]] eq CAny)
assert(implicitly[Contra[Any]] eq CAny)
assert(implicitly[Cov[Any]] eq CAny)
assert(implicitly[Inv[Int]] eq CInt)
assert(implicitly[Cov[Int]] eq CInt)
assert(implicitly[Contra[Int]] eq CAny)
assert(implicitly[Contra[String]] eq CAny)
assert(implicitly[Contra[_ >: String]] eq CAny)
assert(implicitly[Cov[_ >: String]] eq CAny)
assert(implicitly[Cov[_ >: Int]] eq CAny)
assert(implicitly[Specific[Any]].a eq CAny)
assert(implicitly[Specific[Int]].a eq CInt)
assert(implicitly[Specific[String]].a eq CAny)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment