Skip to content

Instantly share code, notes, and snippets.

@erichonorez
Last active February 18, 2019 20:32
Show Gist options
  • Save erichonorez/f5bca7529c674b8c497c304bbe874d8e to your computer and use it in GitHub Desktop.
Save erichonorez/f5bca7529c674b8c497c304bbe874d8e to your computer and use it in GitHub Desktop.
Covariance & Contravariance example
package example
trait Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
trait SmallAnimal extends Animal
case class Mouse(name: String) extends SmallAnimal
trait Printer[-T] {
def print(t: T): String
}
class AnimalPrinter extends Printer[Animal] {
override def print(t: Animal): String = "Animal" + t.name
}
class CatPrinter extends Printer[Cat] {
override def print(t: Cat): String = "Cat " + t.name
}
object Test {
def main: Unit = {
val printCat: Cat ⇒ Printer[Cat] ⇒ String = cat ⇒ {
printer ⇒ {
printer.print(cat)
}
}
print(
printCat(new Cat("Jules"))(new AnimalPrinter())
)
type A = Cat ⇒ SmallAnimal
val a: A = c ⇒ Mouse(name = "Mickey")
type B = Animal ⇒ Mouse
val b: B = a ⇒ Mouse(name = "Mickey")
val c: A = b
/*
* Liskov substitution principle states that:
* if B <: A then everything one can to do with a value of type A
* on should also be able to do with a value of type B
*
* In other words, if (Animal ⇒ Mouse) is a subtype of (Cat ⇒ SmallAnimal) then I should be
* able to substitute (Cat ⇒ SmallAnimal) by (Animal ⇒ Mouse).
*
* In need to have the food of a cat (a function Cat ⇒ SmallAnimal). What I have under my hand is
* a function that provide a mouse for all animals (Animal ⇒ Mouse). If it can provide the food for
* all animals it can provide the food for a Cat. And because A mouse is a small animal (Mouse <: SmallAnimal)
* (Cat ⇒ SmallAnimal) can be substitued by (Animal ⇒ Mouse).
*/
c(new Dog("Ya")) // doesn't compile
c(new Cat("Ya"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment