Talk:Covariance and contravariance (computer science)

From Wikipedia, the free encyclopedia
Jump to: navigation, search
WikiProject Computer science (Rated Start-class, High-importance)
WikiProject icon This article is within the scope of WikiProject Computer science, a collaborative effort to improve the coverage of Computer science related articles on Wikipedia. If you would like to participate, please visit the project page, where you can join the discussion and see a list of open tasks.
Start-Class article Start  This article has been rated as Start-Class on the project's quality scale.
 High  This article has been rated as High-importance on the project's importance scale.
 
edit·history·watch·refresh Stock post message.svg To-do list for Covariance and contravariance (computer science):
  • nonvariance (i.e. unused type variables)

"Argument types" vs. "Parameter types"[edit]

I think it would be clearer if this article referred to parameter types (as in, "contravariant method parameter type") instead of argument types. It's not a huge issue since the examples show the intended meaning, but the term itself is potentially confusing because "contravariant argument type" could also refer to something like this:

obj.foo(new Base()); as opposed to: obj.foo(new Derived());

Covariance and contravariance do not necessarily have the same meaning regarding arguments as they do with parameters. You could have a subclass method (call it bar()) whose parameter was contravariant in comparison with its base class method, but pass it an argument that was covariant as compared to some other call to bar(). So basically, the meaning depends on whether we're talking about the relationship between the methods themselves, or the calls to those methods. Using the term "parameter" instead of "argument" would avoid that ambiguity. Crunch483 (talk) 09:04, 12 June 2016 (UTC)

I feel like the words "argument" and "parameter" are synonyms, so changing from one to another will not disambiguate anything. Vilhelm.s (talk) 00:20, 13 May 2016 (UTC)
Technically an argument is what you pass to a function and a parameter is what the function expects/receives. So they're close to being synonymous but do have different meanings. Many if not most programmers are familiar with this distinction. Crunch483 (talk) 09:04, 12 June 2016 (UTC)

Incorrect ordering in Function Types section?[edit]

In the function types section it states:

S1 → S2 ≤ T1 → T2 if T1 ≤ S1 and S2 ≤ T2.

I think this should be

T1 → T2 ≤ S1 → S2 if T1 ≤ S1 and S2 ≤ T2.

Reasoning: if T1 ≤ S1 then T1 is less general than S1 so clearly T1 → T2 can not be used in all places when S1 → S2 can. Hence T1 → T2 is less general than S1 → S2 and hence it should state T1 → T2 ≤ S1 → S2. 174.21.61.28 (talk) 01:07, 14 June 2015 (UTC)

It's not a typo, the correct rule switches the ordering for the function domain but not the function range. This is definitely the trickiest fact about subtyping, if functions were not contravariant like this, there probably wouldn't be a Wikipedia article in the first place. Note that S ≤ T means "S is _more_ general than T" (maybe this is part of what confused you?). Vilhelm.s (talk) 13:53, 14 June 2015 (UTC)

Way too complex article!![edit]

I am a java programmer with 8 years of experience. When I end up sitting pretty much baffled by what I read here, there is something fundamentally flawed with the article. Many of these computer science articles are way to tied into the theoretical underpinnings, which is very sad for people actually trying to use Wikipedia as a tool to learn and/or understand things, and to do a "quick look-up" of some aspect. Such theory is obviously important for a complete discussion of the aspect, but should OBVIOUSLY come as a distinct chapter later. The intro should be in a "layman terms" language, importantly exemplified with an example written in some NORMAL generic pseudo-language (not any lisp-like silliness - what stupid idea is that?!), as in "This exemplifies the aspect under discussion". I must say that it is obvious that the hardcode theory geeks are WAY too much in control for the comp.sci. articles, making them read like scientific articles seemingly written for journals - and as I've understand the theory of WP, this is not its intention. Stolsvik (talk) 14:43, 18 December 2008 (UTC)


I second your opinion. The article would also need some preable like "if you come from python, stop reading here or you'll become blind" :) 81.208.7.130 (talk) 08:48, 19 May 2009 (UTC)

I believe that the first paragraph should contain a simple, concrete example and relate it to what most OO programmers understand. Perhaps something like:

Many type systems allow instances of a subclass to be treated as if they were instances of their superclass. This is known as the [Liskov substitution principle]. When a type system allows generic types, other situations come up in which you may want to be able to substitute one class for another. For example, if you want to be able to treat a List<Hedgehog> as if it were a List<Animal>, then List would be said to be *covariant*. If you want to be able to treat an Action<Animal> as if it were an Action<Hedgehog>, then Action would be said to be *contravariant*. Kybernetikos (talk) 16:37, 30 October 2012 (UTC)

Green check.svg Done. I have changed the introduction to be more along the lines you suggest Vilhelm.s (talk) 21:18, 6 October 2013 (UTC)

Computer science vs category theory[edit]

This really needs to be cleaned up with some explanation that is not so heavily tied to object-oriented programming. --Saforrest 06:17, 18 April 2006 (UTC)

Go on then, be bold! Most of my knowledge of co/co is limited to an OO context, so I'm not in a position to write it sadly. It might be worth noting that it's Covariance and contravariance (computer science) not Covariance and contravariance. StephenFalken 06:29, 18 April 2006 (UTC)
Yes, it applies to OO but the terms come from category theory as applied to types in programming languages. I'm far from being an expert in the topic, but after reading here and there and not finding a concrete answer I decided to edit the page with what I found. Hope it helps. / Carlos Aya 03:58, 5 September 2006 (UTC)
Ah, please check the spelling / writing style as english is not my mother tongue. / Carlos Aya 04:05, 5 September 2006 (UTC)

Well, I think we have something clean, explaining the terms in general and applied to OO. The languages part section at the end needs review. Carlos Aya 05:43, 20 September 2006 (UTC)

I agree -- I think is is very important that the OO language application details remain. There should be some discussion on the relationship with generics. Adw2000 14:30, 14 June 2007 (UTC)

Instead, I do think that introducing the definition in terms of category theory is the wrong thing to do - the current introduction is too abstract, and difficult to grasp even for someone who knows the term. Even because, as noted below, the definition of type operator is missing. I think that there is an array type operator, building the type "array of X" from the type "X"; and there is a function definition operator, as explained in the article (after the introduction), but it is unobvious to the expert - it is unusual to talk about subtype relationship for function types.
Also, the usual mention of covariance and contravariance is about types of return arguments and parameters in member functions for subclasses; I can apply the initial definition only by saying that member functions of a subclass must be of subtypes of the member function of the base class, but I've never heard such a statement.
I'd start by giving the usual definition, see for instance [1], and then elaborate on generalizations. Actually, that's not a very good source IMHO (I don't think that C++ can allow covariant parameter types), but that's the first Google entry which gives the standard definition. --Blaisorblade (talk) 01:21, 15 July 2008 (UTC)
Ok, Java array types are covariant, but they aren't statically type safe - this anyway means that the discussion on read-only and write-only arrays is moot. I'd just say that support for insert requires covariance and support for read operator requires contravariance, thus mutable arrays are invariant, or they aren't typesafe. --Blaisorblade (talk) 01:39, 15 July 2008 (UTC)

Contravariance and Generic Programming[edit]

This should mention the fact that generic programming supports covariant arguments. For example, adding an element to an STL BackInsertionSequence of type X means adding an X::value_type whereas std::vector<int> (which is a BackInsertionSequence) means adding an int. While int is std::vector<int>::value_type, it is not a subtype of X::value_type. —Ben FrantzDale 18:27, 15 June 2007 (UTC)

Green check.svg Done. This was already fixed by someone; now the page explains clearly why that's not covariance. --Blaisorblade (talk) 02:24, 15 July 2008 (UTC)

Sentence needs editing[edit]

The following sentence is very cumbersome. Could someone who understands the issues improve it?

"How types are built from basic types, thus defining the sub-type relationship, and how new methods are defined and override or not existing methods depends on the language and sometimes not necessarily follow the substitution principle above adding runtime checking instead."

Dougher (talk) 03:00, 28 November 2007 (UTC)

I took a stab at improving it, but don't know for sure if it's any better now, since I come from a programming background as well. --81.243.7.205 (talk) 09:38, 9 June 2008 (UTC)

Bad example[edit]

The first example is unclear if not broken:

"The array type is usually covariant on the base type: since String ≤ Object then ArrayOf(String) ≤ ArrayOf(Object)."

The definition talks about type operators being either covariant, contravariant or invariant. Now suddenly the array type is supposed to be covariant?

"if insert and remove operators are permitted, then the insert operator is covariant (e.g. one can insert a String into an ArrayOf(Object)) and the remove operator is contravariant"

Insert and remove are not type operators. So again, how does this relate to the definition?

I think the example should mention that type safety requires

  1. ArrayOf to be covariant for read only arrays,
  2. ArrayOf to be contravariant for write only arrays,
  3. and ArrayOf to be invariante otherwise.


--83.77.239.59 (talk) 16:24, 25 December 2007 (UTC)

I've mentioned the array "type operator", what you describe as ArrayOf, since I felt the same problem.
Btw, the whole discussion seems irrelevant since there are no write-only array and few read-only ones; I should check, but I think that Java for instance should have invariant array types; I'm sure instead it has invariant generics types, because the issue with ArrayOf applies also to generic collections.
In fact, in C++, when one builds an array type equivalent to Java arrays (i.e. an array of pointers), one discovers that the type of pointers to such arrays is invariant, and that no special rules were created for read-only arrays. Indeed, neither of 'const A**' and 'const B**' is implicitly convertible to the other (nor static_cast is useful here - an old-style cast or a reinterpret_cast<> is required). --Blaisorblade (talk) 01:33, 15 July 2008 (UTC)
I have rewritten the discussion of arrays, I hope this is more clear Vilhelm.s (talk) 21:18, 6 October 2013 (UTC)

This falls under the same title, but I mean the very first example - double vs float. The example, in my opinion, poorly represents the relation of types, I'd suggest using types like `real' and `rational' instead, because float isn't a variant of double and double isn't a variant of float. Here is why: most commonly used floats are 32-bits, 64-bits and 128-bits floats, the size and the precision of the float commonly don't depend on the system and the language that uses them. Double is a type used in much fewer languages and really means "two times the size of the int(eger)", where what is integer is left for the language and / or system to define. More yet, numbers like negative zero, infinities and not-a-number aren't representable in double and the number of bits in double may or may not store the information contained in the float - depends what float and what double you are talking about. Commonly, floats are signed, double may or may not be signed. Float may represent numbers larger then those that may be represented in double, but not all doubles can be precisely represented in float - this depends on the number of bits the float uses, the precise format and so on. The example may be intuitive, to an extend, for C++ programmers, but, not even for them, because it really depends on the compiler you use and sets of defines etc... Also, when the article uses the word "narrow" to mean "more specific" it contradicts itself when using the word "narrow" as in type that has fewer properties (which would be exactly the opposite - "less specific"). I'd rather be in favor of eliminating "narrow" places, where it refers to the type signature being visually narrower then those where "narrow" means "specific". — Preceding unsigned comment added by 84.108.228.145 (talk) 12:53, 18 October 2011 (UTC)

 :Green check.svg Done. Ok, I have changed all the examples to be in terms of Cats and Animals instead of doubles and floats.

Ordering[edit]

The first sentence says

A covariant type operator in a type system preserves the ordering ≤ of types.

Fine, but what is this ordering? This article does not explain it, and neither does type system

The very model of a minor general (talk) 21:53, 1 April 2008 (UTC)

Green check.svg Added a link and explained this more clearly in the intro.--Blaisorblade (talk) 02:27, 15 July 2008 (UTC)

What is covariant?[edit]

The first sentence says that a type operator may be covariant or contravariant. The rest of the article speaks about covariant or contravariant types. What does it mean for a type to be covariant?

Also: I am sure we have an article explaining what a "type operator" is; please link to it.

--The very model of a minor general (talk) 19:50, 4 April 2008 (UTC)

I agree. I made a stab at cleaning it up. —Ben FrantzDale (talk) 03:20, 6 April 2008 (UTC)
Covariance/Contravariance are not properties of a type or a method (function, procedure) alone. Rather, they are relations between a method and its argument and result types. Whenever a contravariant type is mentioned, it must be clear from the context what method it is being related to and what position (argument v. result) in the method it is taking. —Preceding unsigned comment added by 118.68.180.142 (talk) 21:07, 6 June 2008 (UTC)
I can't agree more! Yet in this article, whenever the word covariant or contravariant is used, the context is not clear. It would make sense to say that the type returned by a function is covariant to acceptor's type. The returned type alone is neither covariant, nor contravariant, these adjectives aren't applicable to only one object out of context / not compared to another object. — Preceding unsigned comment added by 84.108.228.145 (talk) 12:35, 18 October 2011 (UTC)

Fact on Castagna's work[edit]

The sentence

"it was shown by Castagna (1995) that all depends on the method fetching algorithm: types used to select the method are contravariant; types not used to select the method are covariant. It is immaterial if the fetching occurs at run-time or at compile time."

is completely wrong. Castagna (1995) has proved exactly the opposite: "given a method m selected by a messages with parameters, when m is overridden, the parameters that determine the (dynamic) [method] selection must be covariantly overridden (i.e., the corresponding parameters in the overriding method must have a lesser type). Those parameters that are not taken into account in the selection must be contravariantly overridden (i.e., the corresponding in the overriding method must have a greater type.)" —Preceding unsigned comment added by 118.68.180.142 (talk) 08:16, 7 June 2008 (UTC)

Ok, I believe you read the work (I haven't myself), and I understand that Castagna and the article have different contexts. What the article says is more ambiguous, and is correct about overloading, not about overriding. I'll try to read the article and fix out the issue, but the statement you take from the article seems pretty obvious for single-dispatch. --Blaisorblade (talk) 02:33, 15 July 2008 (UTC)
Green check.png Yes, I confirm what you say, and the sentence in the article was completely wrong. I fixed it, and left mention of the original content, explaining it is about overloading (Castagna's article talks about overloading too, but I use overloading in the C++/Java meaning, i.e. static overload, not multiple dispatch). --Blaisorblade (talk) 03:07, 15 July 2008 (UTC)

Overview of covariance/contravariance in C# 4.0[edit]

Some relevance towards covariance/contravariance has changed in C#4.0 [2]. Maybe a note should be made of this...

Links to category theory[edit]

Excellent -- the article is at just about the level I was looking for. In particular I was looking for the link to category theory.

However the discussion in 'Origin of the terms' seemed a little confused, with a mention of 'arrows' where I think 'morphisms' was intended, and a rather worrying 'supposedly'. I have been bold and edited this to fit my understanding (unfortunately I wasn't logged in when I did so), but it would be good if someone with a fully secure understanding of the relationship to category theory could check that I haven't said anything incorrect. NormanGray (talk) 13:52, 17 August 2011 (UTC)

Some not clear sentence[edit]

Note, types may share values yet not be equivalent. For example, types assuming values {a,b} and {b,c}, respectively, are not equivalent to each other...though they are equivalent to a type assuming the values {b} since {b}->{a,b} and {b}->{b,c}.

What a mess, equivalence implies transitivity; so you cannot tell that "A and B are not equivalent, though they are equivalent to C".

You should really define what you mean with "equivalent", and use an other word IMO. Sedrikov (talk) —Preceding undated comment added 14:10, 15 September 2011 (UTC).

"Assuming no side effects are permitted"[edit]

In my opinion, the phrase "Assuming no side effects are permitted" shouldn't be included. What I assume JC Chu is trying to say here is "Assuming the type system is sound", but this is an assumption you always implicitly make. Languages that allow side-effects that are not explicitly encoded into the type system of course tend to have an unsound type system... —Ruud 12:29, 5 July 2012 (UTC)

I think JC Chu may be confusing some kind of behavioral subtyping (like in the Liskov substitution principle) for the static subtyping this article is about. Co/contravariance has nothing to do with the actual behavior of the functions beyond the type signature. If the type signature doesn't mention side-effects, then it is type-safe to substitute a function if it respects the co/contravariant function subtyping rule, whether there are side effects or not. That doesn't mean the substitution will be semantics/behavior preserving: there are usually many different functions with the same type signature. Glaucus (talk) 13:15, 5 July 2012 (UTC)
Yes—and the article should probably mention this as well—but this has even less to do with side-effects: even substituting one pure function for another can break behavioural subtyping.—Ruud 13:38, 5 July 2012 (UTC)
What I was trying to say is that with the type theoretic definition of subtype relation on function types given in the article, you cannot replace calls “everywhere” without assuming that no side effects are permitted. JC Chu 14:14, 5 July 2012 (UTC) — Preceding unsigned comment added by JC Chu (talkcontribs)
That assumption seems neither necessary if you're talking about type correctness, nor sufficient if you're talking about semantic correctness. Could you give a concrete example where you think allowing side-effects would cause a problem for type correctness? —Ruud 14:23, 5 July 2012 (UTC)
You’re right. :( Side effect–freedom is not sufficient for behavior equivalence. I still think that “everywhere” is misleading, though. JC Chu 14:34, 5 July 2012 (UTC) — Preceding unsigned comment added by JC Chu (talkcontribs)
I agree. The way it reads right suggests that you can just swap in function calls. It's really less about making function calls and more about passing functions as an argument. If you expect a function of type A -> B, I can pass in a function of type A' -> B' as long as A' :> A and B :> B', because you can always use an "A' -> B'" like an "A->B". Glaucus (talk) 15:36, 5 July 2012 (UTC)
I think it’s better to not mention “f can replace g” at all—just “fg since it cares less …” should be enough. JC Chu (talk) 01:35, 6 July 2012 (UTC)

Contradiction at the beginning[edit]

contravariant: converting from a general type (Shapes) to a more specialized type (Rectangles)
For example, a type W that may hold one of the values from the set {a,b,c,d} is wider than a type N that may only hold values from the narrower set {a,b}. Hence, a type conversion from W to N, such as in the case of passing a double to a function expecting a float, is a covariant conversion.

In the example, shouldn't converting from double to float be contravariant? Will Faught (talk) 01:07, 21 January 2013 (UTC)

I agree. This seems to be a contradiction. The Liskov substitution principle page seems to agree with the example rather than the definitions. For the LSP, method arguments can only be widened in a subtype. This is given as contravariance. However, here contravariance is described as specializing a type. This is confusing. Sftrabbit (talk) 11:24, 9 February 2013 (UTC)
Green check.svg Fixed. — Preceding unsigned comment added by 18.111.23.137 (talk) 08:49, 7 May 2013 (UTC)

English article lacks diagrams, German article has very good ones[edit]

I usually prefer English wikipedia, but the German article is much better. There you can actually see what it means with all the diagrams. It would be great if someone put the diagrams into this article. (I'd do it myself but I have no experience with wikipedia.) — Preceding unsigned comment added by 212.254.197.250 (talk) 07:48, 16 June 2014 (UTC)

Ok, I have done this. Vilhelm.s (talk) 03:04, 23 June 2014 (UTC)

"Invariant" vs "Bivariant" vs "Nonvariant"[edit]

Suppose A≤B. There is a terminological split about what to call a type constructor T such that neither T<A> ≤ T<B> or T<B> ≤ T<A>; is this "invariant" or "non-variant"? Similarly, if both T<A>≤T<B> and T<B>≤T<A>; is this "invariant" or "bivariant"?

If we go through the current list of references in the article,

  • Altidor et al., "Taming the Wildcards" uses "invariant" meaning neither, "bivariant" meaning both.
  • Eric Lippert's "Exact rules for variance validity" states that a type is "valid invariantly" if it does not contain type parameters which declared covariant or contravariant. So this is not quite the same concept as the variance of a type constructor.
  • The ECMA standard that Lippert quotes doesn't use "invariant" at all, it uses the description "behaves non-variantly" for the same concept, and also speaks of "non-variant" parameters.
  • "Scalable component abstractions" uses "non-variant" meaning neither. No term used meaning both.
  • Tate, "Mixed-site variance" uses "invariant" meaning neither. No term used meaning both.
  • Igarashi and Viroli "On Variance-Based Subtyping for Parametric Types", uses "invariant" meaning neither and "bivariant" meaning both. (In a footnote they say one should not use "bivariant" meaning _neither_---I should hope so!).
  • Kresten Krab Thorup; Mads Torgersen "Unifying Genericity: Combining the Benefits of Virtual Types and Parameterized Classes" uses "nonvariant" meaning neither. No term used meaning both.
  • Tate, Leung, and Lerner, "Taming wildcards in Java's type system" uses "bivariant" meaning both. No term used meaning neither.

The other references do not mention these terms. So in this sample, there seems to be an even split between "nonvariant" and "invariant" as a term for "neither", and nobody uses "invariant" to mean "both". I've updated the article to reflect this.

Vilhelm.s (talk) 16:50, 26 March 2014 (UTC)

@Vilhelm.s: The current definitions you put in the article are completely wrong/ambiguous/non-sensical. I'm currently not in my office, so quotes from reliable sources will have to wait until tomorrow, but:
  • Consider a type . The type parameter is contravariant (" is contravariant in its first parameter"), the type parameter is covariant (" is covariant in its second parameter"). I think we both agree on that.
  • Consider a type . Because the type parameter is used both in a covariant and a contravariant position of the function space constructor, if then we must have that and , thus that . Ergo, the first type parameter cannot change, it is invariant (see the dictionary definition of that word: invariant (adjective): "never changing").
  • Consider the same type , the type parameter is not actually used so you can put anything in there without violating the subtyping relation. Thus the variance does not matter and the type parameter is nonvariant. This is somewhat of a pathological case, so the term is rarely used in practice.
  • You current wording "if both of these apply" and "if neither of these applies" is highly ambigous/underspecificed, so it is hard to even begin to argue whether they are right or wrong, but: I have never seen any text use the word "nonvariant" in such a way that means the same as "invariant", as your definition currently claims; I have seen any text use the word "bivariant", so I cannot say whether is is synonymous with invariant or nonvariant.
Please revert the definition back to my version for now. —Ruud 14:56, 14 December 2014 (UTC)
@Ruud Koot: I don't want to revert to your version, because it claims that 'invariant' and 'nonvariant' have different meanings. If you look through the list of citatations I quoted above, you see that they were always used to mean the same thing. (Of course, if you can find examples of other authors using it differently, it might be worth adding a usage note saying that that there are mixed conventions, or something, but when I looked I could not find any evidence of that.)
Let me go through your list of examples. (1) Yes, we agree on co- and contravariant. (2) Yes, I would call this "invariant". However, the literature is mixed, about half of the papers cited (and I think also the C# documentation) calls this case "nonvariant". You say you have never seen any text use the word in this way—please refer to the list of papers above! ☺ (3) I think the standard term for this kind of unused type parameters is "bivariant". All the papers above that mention this concept use that word.
If we agree on the facts of the matter, you are very welcome to clarify the text in the definition. (To be honest, I thought what you wrote was ambiguous and hard to understand too—I think the only way to bring clarity is to have some examples in there). —Vilhelm.s (talk) 20:18, 14 December 2014 (UTC)
@Vilhelm.s: Also, you seem to think variance is a property of a type constructor. It really is property of the arguments/parameters of a type constructor. Obviously, if a a type constructor only has one parameter then people will sometimes be sloppy/concise and talk about the variance of a type or type constructor when they really mean the variance of the only argument of that type. Sometimes this is even done if a type has multiple parameters and they all have the same variance. For types with multiple arguments and differing variances, such as the function space constructor, this distinction really starts to matter, though. —Ruud 15:28, 14 December 2014 (UTC)
Yes, contravariance is a property of a type constructor, not of an argument. This is the usual convention in mathematics, for example we say that sin(x) is continuous, or that log(x) is monotone—we don't say that x is a continuous argument, or that x is a monotone argument. If you want some examples in the literature, see e.g. Robert Harper's "Practical Foundations for Programming Languages" (www.cs.cmu.edu/~rwh/plbook/book.pdf):

A type constructor is said to be covariant in an argument if subtyping in that argument is preserved by the constructor. It is said to be contravariant if subtyping in that argument is reversed by the constructor. It is said to be invariant in an argument if subtyping for the constructed type is not affected by subtyping in that argument.

or Benjamin Pierce's "Types and Programming Languages":

We have seen a number of examples of covariant type constructors (records and variants, as well as function types, on their right-hand sides) and one contravariant constructor (arrow, on the left-hand side). The List constructor is also covariant [...]

I know that there are some sources that talk about "a covariant argument", etc. I'm not sure where this practice started, but I think it got popular because the Microsoft C# and CLR documentation uses this phrasing. However, I think it's basically wrong, and Wikipedia should not perpetuate it. —Vilhelm.s (talk) 20:18, 14 December 2014 (UTC)
@Vilhelm.s: No, you are misinterpreting those sources! Let me quote the the first again, but with some emphasis added: "A type constructor is said to be covariant in an argument ...". The exact same thing happens with continuity in mathematics: for a function of multiple variables one can say it is continuous in a particular variable. Pierce is simply using the shorthand I spoke about earlier: for type constructors with only one argument (note how he has to speak about "arrow, on the left-hand side"), it's already obvious which argument you are talking about. —Ruud 22:20, 14 December 2014 (UTC)
Sure, I don't think we disagree about any factual matter here, just terminology. My claim is that you should never say that an argument is covariant, you should say that the type constructor is covariant [in the nth argument]. You can leave out the part "in the nth argument" in cases where there only is one. —Vilhelm.s (talk) 22:29, 14 December 2014 (UTC)
Okay, then we nearly agree. I'll do a literature search tomorrow, it could be that there is some difference in terminology between the FP/TT and the OO communities. —Ruud 22:56, 14 December 2014 (UTC)

What is S-ly?[edit]

At declaration site variance annotations section, in talk about interface suddenly this document says about valid S-ly. But I don't quite get it. I think it needs a bit more clarification about S-ly itself. — Preceding unsigned comment added by Miauk3 (talkcontribs) 23:51, 18 July 2015 (UTC)

The idea is that *S* ranges over "covariant" and "contravariant", and (not-S) flips the sign. This is how the CLR specification is written. I guess another way to write it would be using that obnoxious mathematical "foo (bar)" style, something like "a type is valid covariantly (contravariantly) if: ...Ai is valid contravariantly (covariantly), and the ith parameter to G is declared contravariant, ...". I don't know what is best. Vilhelm.s (talk) 17:44, 19 July 2015 (UTC)

Mistake (position co(ntra)variance)[edit]

"...it is easy to calculate which positions are co- and contravariant: a position is covariant if it is on the left side of an even number of arrows."

Wrong. A'→B→B ≤ A→B→B if A≤A', since function types are right-associative by default (so A→B→B = A→(B→B)). Type theory — Preceding unsigned comment added by 217.71.45.3 (talk) 18:46, 4 November 2015 (UTC)

Yeah, you need to look at the syntax tree of the type, not just the textual representation. Maybe say "under the left side" instead of "on the left side"? You could spell it out more pedantically, "a position is covariant if, when considering the type as an abstract syntax tree, a path from the root to the position passes through (the left side of) an even number of arrow type constructors", but it sounds kindof clumsy. I figure the intended meaning is probably clear from the context? Vilhelm.s (talk) 22:50, 4 November 2015 (UTC)
I agree that the alternative formulations you proposed are opaque but it's just wrong as it stands, so we should think of a better way of formulating it. I substituted "an even number of arrows" with "an even number of arrows applying to it" — Preceding unsigned comment added by 217.71.47.18 (talk) 13:46, 5 November 2015 (UTC)

Just want to say, this is a great article[edit]

This is a great article that explains a tricky subject very well. Thank you everyone who has worked on this. — Preceding unsigned comment added by 104.156.100.85 (talk) 13:01, 13 February 2016 (UTC)

C# examples[edit]

In general, I think this is a great article. However, it might help to explain why in the C# examples IEnumerable is covariant while Action is contravariant. The current explanation assumes knowledge of C# that mahy readers probably don't have.173.164.34.106 (talk) 15:28, 18 March 2016 (UTC)