Covariance and contravariance are properties of mappings between sets Consider the following two sets of types: { Animal, Tiger, Fruit, Banana } And this clearly related set: { IEnumerable, IEnumerable, IEnumerable, IEnumerable } There is a mapping from the first set to the second set. That is, for each T in the first set, the corresponding type in the second set is IEnumerableThere is an assignment compatibility relationship between pairs of types in the first set. A value of type Tiger can be assigned to a variable of type Animal.
Let's write "a value of type X can be assigned to a variable of type Y" in a shorter form: X ⇒ Y So: Tiger ⇒ Tiger Tiger ⇒ Animal Animal ⇒ Animal Banana ⇒ Banana Banana ⇒ Fruit Fruit ⇒ Fruit In C# 4 there is an assignment compatibility relationship between pairs of types in the second set IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE ⇒ IEIC ⇒ IC IC ⇒ IC IC ⇒ IC Backwards! IC ⇒ IC ⇠ICContravariance reverses it.
" Covariance and contravariance are properties of mappings between sets. Consider the following two sets of types: { Animal, Tiger, Fruit, Banana }. And this clearly related set: { IEnumerable, IEnumerable, IEnumerable, IEnumerable } There is a mapping from the first set to the second set.
That is, for each T in the first set, the corresponding type in the second set is IEnumerable. Or, in short form, the mapping is T → IE. With me so far?
There is an assignment compatibility relationship between pairs of types in the first set. A value of type Tiger can be assigned to a variable of type Animal. Let's write "a value of type X can be assigned to a variable of type Y" in a shorter form: X ⇒ Y.
So: Tiger ⇒ Tiger Tiger ⇒ Animal Animal ⇒ Animal Banana ⇒ Banana Banana ⇒ Fruit Fruit ⇒ Fruit In C# 4 there is an assignment compatibility relationship between pairs of types in the second set. IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE IE ⇒ IE Notice that the mapping T → IE preserves the existence and direction of assignment compatibility. That is, if X ⇒ Y, then IE ⇒ IE.
A mapping which has this property is called a "covariant mapping". Now consider the set { IComparable, IComparable, IComparable, IComparable } now we have the mapping from the first set to the third set T → IC.In C# 4: IC ⇒ IC IC ⇒ IC Backwards! IC ⇒ IC IC ⇒ IC IC ⇒ IC Backwards!
IC ⇒ IC That is, the mapping T → IC has preserved the existence but reversed the direction of assignment compatibility. That is, if X ⇒ Y, then IC � IC.
Such a mapping is called a contravariant mapping. So that's the difference between covariance and contravariance. Covariance preserves the direction of assignability.
Contravariance reverses it.
1 brilliant explanation, after all you made it yourself! :) – this. __curious_geek Feb 4 '10 at 19:03 One of the .
Net 4.0 features I can't wait to play around with. :) – Arnis L. Feb 23 '10 at 11:13 +1 One of the better explanations of these concepts I've seen.
– dkackman Mar 31 '10 at 21:49.
Eric Lippert has a series of posts on his blog about *variance, both from a conceptual perspective and how they relate to C#. Try starting here: blogs.msdn.com/ericlippert/archive/tags/....
It's probably easiest to give examples - that's certainly how I remember them. Covariance Canonical examples: IEnumerable, Func You can convert from IEnumerable to IEnumerable, or Func to Func. Values only come out from these objects.It works because if you're only taking values out of the API, and it's going to return something specific (like string), you can treat that returned value as a more general type (like object).
Contravariance Canonical examples: IComparer, Action You can convert from IComparer to IComparer, or Action to Action; values only go into these objects. This time it works because if the API is expecting something general (like object) you can give it something more specific (like string). More generally If you have an interface IFoo it can be covariant in T (i.e.
Declare it as IFoo if T is only used in an output position (e.g. A return type) within the interface.It can be contravariant in T (i.e. IFoo) if T is only used in an input position (e.g. A parameter type). It gets potentially confusing because "output position" isn't quite as simple as it sounds - a parameter of type Action is still only using T in an output position - the contravariance of Action turns it round, if you see what I mean.
Usually this sort of thing doesn't come up, fortunately :).
I think "in" is fine there; "over" might work too. – Jon Skeet Feb 2 '10 at 14:16.
Read up all of the articles by Eric Lippert on Covariance and Contravariance. He is one of the writers of the C# compiler and reading through the series of posts above is a great way to understand the differences. This is the first part.
IMO, the OP should probably start with the first in the series: blogs.msdn. Com/ericlippert/archive/2007/10/16/… – Ryan Emerle Feb 2 '10 at 14:13 @Ryan Emerle - added link to first series entry. – Oded Feb 2 '10 at 14:30.
Covariance and Contravariance in C#, Part Eight: Syntax Options Covariance and Contravariance in C#, Part Nine: Breaking Changes Covariance and Contravariance in C#, Part Ten: Dealing With Ambiguity.
I hope my post helps to get a language-agnostic view of the topic. For our internal trainings I have worked with the wonderful book "Smalltalk, Objects and Design (Chamond Liu)" and I rephrased following examples. What does “consistency�
Mean? The idea is to design type-safe type hierarchies with highly substitutable types. The key to get this consistency is sub type based conformance, if you work in a statically typed language.
(We'll discuss the Liskov Substitution Principle (LSP) on a high level here.) Practical examples: Covariance: Let's assume Birds that lay Eggs “consistently� With static typing: If the type Bird lays an Egg, wouldn't Bird's subtype lay a subtype of Egg? E.g.
The type Duck lays a DuckEgg, then the consistency is given. Why is this consistent? Because in such an expression:Egg anEgg = aBird.Lay();the reference aBird could be legally substituted by a Bird or by a Duck instance.
We say the return type is covariant to the type, in which Lay() is defined. A subtype's override may return a more specialized type. => “They deliver more.
€? Contravariance: Let's assume Pianos that Pianists can play “consistently� With static typing: If a Pianist plays Piano, would she be able to play a GrandPiano?
Wouldn't rather a Virtuoso play a GrandPiano? (Be warned; there is a twist! ) This is inconsistent!
Because in such an expression: aPiano. Play(aPianist); aPiano couldn't be legally substituted by a Piano or by a GrandPiano instance! A GrandPiano can only be played by a Virtuoso, Pianists are too general!
GrandPianos must be playable by more general types, then the play is consistent. We say the parameter type is contravariant to the type, in which Play() is defined. A subtype's override may accept a more generalized type.
=> “They require less. €? Back to C#: Because C# is basically a statically typed language, the "locations" of a type's interface that should be co- or contravariant (e.g. Parameters and return types), must be marked explicitly to guarantee a consistent usage/development of that type, to make the LSP work fine.In dynamically typed languages LSP consistency is typically not a problem, in other words you could completely get rid of co- and contrvariant "markup" on .
Net interfaces and delegates, if you only used the type dynamic in your types. - But this is not the best solution in C# (you shouldn't use dynamic in public types). Back to theory: The described conformance (covariant return types/contravariant parameter types) are the theoretical ideal (supported by the languages Emerald and POOL-1).
Some oop languages (e.g. Eiffel) decided to apply another type of consistency, esp. Also covariant parameter types, because it better describes the reality than the theoretical ideal. In statically typed languages the desired consistency must often be achieved by application of design patterns like “double dispatching�
And “visitor�. Other languages provide so-called “multiple dispatch� (e.g. CLOS) or get the desired effect by using dynamic typing.
Such a mapping is called a contravariant mapping. So that's the difference between covariance and contravariance. Covariance preserves the direction of assignability.
Contravariance reverses it.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.