Skip to content

Instantly share code, notes, and snippets.

@julienrf
Last active December 14, 2015 04:49
Show Gist options
  • Save julienrf/5031236 to your computer and use it in GitHub Desktop.
Save julienrf/5031236 to your computer and use it in GitHub Desktop.
Contravariance is useful.
// Some data type definitions: the usual (and boring) zoo class hierarchy
abstract class Animal { }
abstract class Mammal extends Animal { }
class Giraffe extends Mammal { }
class Zebra extends Mammal {
num stripeCount;
Zebra(num stripeCount) {
this.stripeCount = stripeCount;
}
}
// Veterinaries treat animals
abstract class Vet<A> {
void treat(A a);
}
// This one only knows how to treat zebras
class ZebraVet extends Vet<Zebra> {
void treat(Zebra zebra) {
print("Treating a zebra with ${zebra.stripeCount} stripes");
}
}
// This one knows how to treat any kind of animal
class AnimalVet extends Vet<Animal> {
void treat(Animal animal) {
print("Treating animal $animal");
}
}
// At this point of the code, it is obvious that `Vet<Animal>` is a subtype of `Vet<Zebra>`
// because a `Vet<Animal>` knows how to treat any animal, including zebras.
// This function needs just a `Vet<Mammal>`
void treatMammal(Vet<Mammal> vet) {
vet.treat(new Giraffe()); // Note that the actual mammal we want to treat is a giraffe
}
// Ok, enough definitions. Let’s run the code.
void main() {
// Can I use a `Vet<Zebra>` to treat a mammal?
// Obviously I can not (because a mammal may not be a zebra and may not have stripes).
// However the Dart analyzer does not complain … but it fails at runtime.
treatMammal(new ZebraVet());
// Can I use a `Vet<Animal>` to treat a mammal?
// Obviously I can, because a mammal *is* an animal.
// However the Dart analyzer warns me: “'AnimalVet' is not assignable to 'Vet<Mammal>'”. This assertion is just wrong.
// Hopefully the compiler lets me compile the code although the analyzer detected a type “error” … and it just runs fine.
treatMammal(new AnimalVet());
}
@julienrf
Copy link
Author

julienrf commented Mar 1, 2013

A Zebra is a Mammal, but a Vet<Zebra> is not a Vet<Mammal> ;)

A Vet<Mammal> is able to treat any Mammal (including a Zebra) while a Vet<Zebra> is only able to treat a Zebra. So a Vet<Mammal> is a Vet<Zebra>!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment