I just learned in my programming languages class that “contravariant argument types would actually be safe, but they have not been found useful and are hence not supported in practical languages.” Even though they are not supported, I am confused as to why something like this example we were given would still be, in theory, “safe”:
class Animal {
...
public bool compare(Panda) { ... }
}
class Panda extends Animal {
...
public bool compare(Animal) { ... }
}
From what I understand, problems with subtyping come up when something is done that could cause a loss of specificity. So what if I did this? :
Panda p = new Panda();
Animal a = new Animal
...
p.compare(a);
When I look at this, it seems like panda could (and probably does) have some extra fields in it that a plain animal wouldn’t know about. Thus, even if all of their animal-specific data members are the same, a panda can have other stuff that differs. How would that make it okay to compare it to a plain animal? Would it just consider the animal-only stuff and ignore the rest?
In your example you don’t use any generic types. You have
PandaextendingAnimal, and it’s an example of inheritance and leads to polymorphism which is more or less what you describe. Check the links.To get contravariance, you need to consider some generic type. I’ll use .NET type
IComparer`1[T]as an example. With C# syntax (which I’ll use rather than Java), we indicate thatICompareris contravariant inTby writinginin the definition:Suppose I have a method which returns an
IComparer`1[Animal](orIComaparer<Animal>), like:Now in C#, it’s legal to say:
Now, this is because of contravariance. Note that the type
IComparer<Animal>does not derive from (or “extend”) the typeIComparer<Panda>. Instead,Pandaderives fromAnimal, and this leads to theIComparer<Xxxx>being assignable to each other (in the opposite order, hence “contravariance” (not “covariance”)).The reason why it’s meaningful to declare a
Comparer<>contravariant, is if you have a comparer that can compare two arbitrary animals, and return a signed number indicating which is greater, then that same comparer can also take in two pandas and compare those. For pandas are animals.So the relation
(from inheritance) leads to the relation
(by contravariance).
For an example with covariance, the same relation
leads to
by covariance (
IEnumerable<out T>).