Covariance and Contravariance - Just different mechanisms for invoking guaranteed base class behavior?

陌路散爱 提交于 2019-12-03 13:52:01
Eric Lippert

I'm having a struggle understanding these two concepts.

Yes you are. Many people do.

But I think after many videos and SO QA's, I have it distilled down to its simplest form:

You have not.

Covariance means that a sub-type can do what its base-type does.

No. That's the Liskov Substitution Principle.

Contravariance means you can treat a sub-type the same way you would treat its base-type.

No. That's just re-stating what you said for covariance.

The real distillation of covariance and contravariance is:

  • A covariant conversion preserves the direction of another conversion.

  • A contravariant conversion reverses the direction of another conversion.

Dog is convertible to Animal. IEnumerable<Dog> is convertible to IEnumerable<Animal>. The direction is preserved, so IEnumerable<T> is covariant. IComparable<Animal> is convertible to IComparable<Dog>, which reverses the direction of the conversion, so it is contravariant.

I understand mathematically what covariance means, and so I guess it's the same in compsci.

Just to be clear: mathematicians use "variance" to mean a bunch of different things. The meaning that is common to mathematics and computer science is the category theory definition.

In C# it's just a matter of where and in what ways these two types of relationships are supported?

Mathematically, variance tells you about whether a relation is preserved or reversed by a mapping. If we have the mapping T --> IEnumerable<T> and the relation "is convertible to via identity or reference conversion" then it is the case that in C#, if X relates to Y then IE<X> relates to IE<Y>. The mapping is therefore said to be covariant with respect to the relation.

what is it that these features are trying to accomplish by supporting them?

People frequently requested "I have a method that takes a sequence of animals and I have a sequence of turtles in hand; why do I have to copy the sequence to a new sequence to use the method?" That's a reasonable request, we got it frequently, and we got it a lot more frequently after LINQ made it easier to work with sequences. It's a generally useful feature that we could implement at a reasonable cost, so we implemented it.

Variance - refers to how complex types (arrays, lists, delegates, generics) relate to the direction of subtyping of their underlying types.

In other words it is about in what direction is allowed to implicitly cast complex types.

Example of the relation of two complex types (delegates) according to their underlying types Animal and Cat.

Covariance is a preserved direction of implicit casting as to subtyping direction (Animal<-Cat)

// Covariance based on type of return param of delegate
var catDelegate = new Func<Cat>(delegate {return null;});

// Allowed implicit casting from delegate based on Cat return param 
// to delegate based on Animal return param 
Func<Animal> animalDelegate = catDelegate;

Contravariance is a reversed direction of implicit casting as to subtyping direction (Animal->Cat)

// contravariance based on type of passed arguments of delegate
var animalDelegate = new Action<Animal>(delegate{});

// Allowed implicit casting from delegate based on Animal passed param 
// to delegate based on Cat passed param
Action<Cat> catDelegate = animalDelegate;

Invariance is a unsupported implicit casting (in any direction)

Generic lists are invariant

List<Animal> animals = new List<Cat>(); // error!
List<Cat> animals = new List<Animal>(); // error!

Examples of supported variance in C#

Arrays are covariant

Animal[] animals = new Cat[10]; // possible

Generic IEnumerable is covariant

IEnumerable<Animal> animals = new List<Cat>(); // possible

I think we are limiting the scope of covariance and contravariance if we are just thinking in terms of base type and sub type and how base type behavior is called. Real merit of contravarinace and covariance comes in terms of what kind of types (projections as explained by Eric lippert http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx) can be created using them. Following faqs on variance should be able to clear your doubt. http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!