Skip to content

Instantly share code, notes, and snippets.

@jcracknell
Last active December 24, 2015 14:29
Show Gist options
  • Save jcracknell/6813110 to your computer and use it in GitHub Desktop.
Save jcracknell/6813110 to your computer and use it in GitHub Desktop.
Examples demonstrating scala's bizzare specificity rules as applied to contravariant types.
class Animal
class Cat extends Animal
abstract class Whisperer[-A <: Animal] extends (A => Unit)
object Whisperer {
implicit def animalWhisperer: Whisperer[Animal] =
new Whisperer[Animal] { def apply(a: Animal): Unit = { println("animal") } }
implicit def catWhisperer: Whisperer[Cat] =
new Whisperer[Cat] { def apply(a: Cat): Unit = { println("cat") } }
}
implicitly[Whisperer[Animal]].apply(new Animal)
implicitly[Whisperer[Cat]].apply(new Cat)
// animal
// animal
class Animal
class Cat extends Animal
abstract class Whisperer[-A <: Animal] extends (A => Unit)
trait AnimalWhisperers {
implicit def animalWhisperer: Whisperer[Animal] =
new Whisperer[Animal] { def apply(a: Animal): Unit = { println("animal") } }
}
trait CatWhisperers extends AnimalWhisperers {
implicit def catWhisperer: Whisperer[Cat] =
new Whisperer[Cat] { def apply(a: Cat): Unit = { println("cat") } }
}
object Whisperer extends CatWhisperers
implicitly[Whisperer[Animal]].apply(new Animal)
implicitly[Whisperer[Cat]].apply(new Cat)
// implicitly[Whisperer[Animal]].apply(new Animal)
// implicitly[Whisperer[Cat]].apply(new Cat)
// /home/cracknj/git/contravariant-resolution/./3.scala:16: error: ambiguous implicit values:
// both method animalWhisperer in object Whisperer of type => this.Whisperer[this.Animal]
// and method catWhisperer in object Whisperer of type => this.CatWhisperer
// match expected type this.Whisperer[this.Cat]
// implicitly[Whisperer[Cat]].apply(new Cat)
// ^
// one error found
class Animal
class Cat extends Animal
abstract class Whisperer[-A <: Animal] extends (A => Unit)
abstract class CatWhisperer extends Whisperer[Cat]
object Whisperer {
implicit def animalWhisperer: Whisperer[Animal] =
new Whisperer[Animal] { def apply(a: Animal): Unit = { println("animal") } }
implicit def catWhisperer: CatWhisperer =
new CatWhisperer { def apply(a: Cat): Unit = { println("cat") } }
}
implicitly[Whisperer[Animal]].apply(new Animal)
implicitly[Whisperer[Cat]].apply(new Cat)
// /home/cracknj/git/contravariant-resolution/./2.scala:19: error: ambiguous implicit values:
// both method animalWhisperer in trait AnimalWhisperers of type => this.Whisperer[this.Animal]
// and method catWhisperer in trait CatWhisperers of type => this.Whisperer[this.Cat]
// match expected type this.Whisperer[this.Cat]
// implicitly[Whisperer[Cat]].apply(new Cat)
// ^
// one error found
class Animal
class Cat extends Animal
abstract class Whisperer[-A <: Animal] extends (A => Unit)
abstract class CatWhisperer extends Whisperer[Cat]
trait AnimalWhisperers {
implicit def animalWhisperer: Whisperer[Animal] =
new Whisperer[Animal] { def apply(a: Animal): Unit = { println("animal") } }
}
trait CatWhisperers extends AnimalWhisperers {
implicit def catWhisperer: CatWhisperer =
new CatWhisperer { def apply(a: Cat): Unit = { println("cat") } }
}
object Whisperer extends CatWhisperers
implicitly[Whisperer[Animal]].apply(new Animal)
implicitly[Whisperer[Cat]].apply(new Cat)
// animal
// cat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment