Questions tagged [contravariance]

Within the type system of a programming language, covariance and contravariance refers to the ordering of types from narrower to wider and their interchangeability or equivalence in certain situations (such as parameters, generics, and return types)

Within the type system of a programming language, a typing rule or a type conversion operator is:

covariant if it preserves the ordering, ≤, of types, which orders types from more specific to more generic;

contravariant if it reverses this ordering, which orders types from more generic to more specific;

invariant if neither of these applies.

These terms come from category theory, which has a general definition of covariance and contravariance that unifies the computer science definition of these terms with the definition used in vector spaces.

This distinction is important in considering argument and return types of methods in class hierarchies. In object-oriented languages such as Python, if class B is a subtype of class A, then all member functions of B must return the same or narrower set of types as A; the return type is said to be covariant. On the other hand, if the member functions of B take the same or broader set of arguments compared with the member functions of A, the argument type is said to be contravariant. The problem for instances of B is how to be perfectly substitutable for instances of A. The only way to guarantee type safety and substitutability is to be equally or more liberal than A on inputs, and to be equally or more strict than A on outputs. Note that not all programming languages guarantee both properties in every context, and that some are unnecessarily strict; they are said not to support covariance or contravariance in a given context; the behavior of some programming languages is discussed below.

Typical examples:

The operator which constructs array types from element types is usually covariant on the base type: since String ≤ Object then ArrayOf(String) ≤ ArrayOf(Object). Note that this is only correct (i.e. type safe) if the array is immutable; 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 (e.g. one can remove an Object from an ArrayOf(String)). Since the mutators have conflicting variance, mutable arrays should be invariant on the base type.

Let f be a function with a parameter of type T and let g be a function with a parameter of type S, both with the same return type. If T ≤ S, then g ≤ f. g can replace f anywhere, since it cares less about the type of its parameter, and both return the same type. Because the subtype relation between the argument type and the functions is reversed, the function type is said to be contravariant on its argument type.

Let f be a function that returns a value of type T and let g be a function that returns a value of type S, both with the same parameter type. If T ≤ S, then f ≤ g. f can replace g anywhere, since it returns only a subset of all possible values returned by g, and both take the same argument. Because the subtype relation between the argument type and the functions is preserved, the function type is said to be covariant on its return type.

In object-oriented programming, substitution is also implicitly invoked by overriding methods in subclasses: the new method can be used where the old method was invoked in the original code. Programming languages vary widely on their allowed forms of overriding, and on the variance of overridden methods' types.

540 questions
6
votes
5 answers

Casting from IEnumerable to IEnumerable
Recently I found a very surprising behavior in c#. I had a method which takes IEnumerable as a parameter and i was passing IEnumerable but it's not possible. While in c# everything can be upcast to Object than why this is not…
Embedd_0913
  • 16,125
  • 37
  • 97
  • 135
6
votes
6 answers

Mediatr with generic handler and query

I am working on a ASP.NET Core 2.2 Web API application with Mediatr. I have a handler that looks like - public class MyQueryHandler : IRequestHanlder, IQueryable> { public Task> Handle(MyQuery myquery,…
Bryan
  • 5,065
  • 10
  • 51
  • 68
6
votes
2 answers

Kotlin Generics type parameters

At the following source code fun main(args: Array) { println("Hello, world!") val mutableIntList = mutableListOf(1, 2, 3) addInt(4, mutableIntList) // No compile-time error addAnotherInt(5, mutableIntList) // Compile-time…
LiTTle
  • 1,811
  • 1
  • 20
  • 37
6
votes
2 answers

Contravariance in Kotlin

I never truly understood generics in Java, so it seems to be the case with Kotlin. Consider the following code snippet (it's a contrived example): class AnyComparator: Comparator { override fun compare(o1: Any, o2: Any): Int { …
Katona
  • 4,816
  • 23
  • 27
6
votes
4 answers

Examples of good, real-life use-cases for covariance and contravariance in C# 4.0?

Before C# 4.0 came out, I was quite excited about covariance and contravariance. It pandered to my fondness for theoretical correctness! However, now that it’s out, and I’m back to writing normal, everyday, boring code, I’m starting to wonder: did I…
Timwi
  • 65,159
  • 33
  • 165
  • 230
6
votes
2 answers

c# Generics "in" keyword

I've recently been assigned to some maintenance work on an existing application. I've come across the following code: public interface IEntityService { T GetEntityById(TKey id); IEnumerable GetAll(); void Update(T…
bgs264
  • 4,572
  • 6
  • 38
  • 72
6
votes
1 answer

Contravariant types and extensibility

I'm writing a C++ library for optimization, and I've encountered a curious issue with contra-variant types. So, I define a hierarchy of "functions", based on what information they can compute. class Function { public: double value()=0; } class…
Jeremy Salwen
  • 8,061
  • 5
  • 50
  • 73
6
votes
4 answers

Covariance vs. contravariance with respect to class inheritance

What is the meaning of the concepts 'covariance' and 'contravariance'? Given 2 classes, Animal and Elephant (which inherits from Animal), my understanding is that you would get a run-time errors if you try and put an Elephant into an array of…
alexmac
  • 4,183
  • 3
  • 29
  • 32
6
votes
2 answers

Contravariance on abstract classes

I would like to create a nice interface on C++ on which each implementation needs to have the addition defined, on itself. I would like to do something like this : class A{ ... virtual A& operator+(const A& other) =0; …
6
votes
0 answers

Why isn't possible to have contravariant return types

I'm playing around with generics in Java, and I found something strange: The following does compile: public static B reduce(Function2 func) { //code doesn't matter } But the following does not: public static
Vinicius Seufitele
  • 885
  • 1
  • 6
  • 15
6
votes
1 answer

Why is it safe not to check object-private or object-protected definitions for their variance position?

I have learned that Scala does not check object-private(private[this]) or object-protected(protected[this]) definitions for their variance position. Why is it safe not to check them? I have read some materials related to it but failed to find a…
dkim
  • 3,930
  • 1
  • 33
  • 37
6
votes
1 answer

Why does Scala compiler say that contravariant type A occurs in covariant position in type >: A <: Any of type B?

The compiler is telling me this can't be with a warning of: "contravariant type A occurs in covariant position in type >: A <: Any of type B." The warning is in the type parameter of the compose method. Logically the type definition makes sense to…
wheaties
  • 35,646
  • 15
  • 94
  • 131
6
votes
1 answer

MonoTouch and supporting variant generic interfaces

The below example compiles fine in regular Mono 2.10.9: namespace covarianttest { public interface ITest : IEnumerable { } } However when I attempt compile it against MonoTouch 6.0.8 I receive this error: Error CS1961: The…
Rodney S. Foley
  • 10,190
  • 12
  • 48
  • 66
6
votes
3 answers

IList using covariance and contravariance in c#, is this possible?

would this be possible? (I don't have vs. 2010, so I can't try it myself, sorry) public interface IComplexList where TOutput : TInput { public IEnumerator GetEnumerator(); public void Add(TInput…
Daniel Fabian
  • 3,828
  • 2
  • 19
  • 28
6
votes
1 answer

Cannot implicitly convert MyType to MyType

I am not sure if this is a Covariance and Contravariance issue but I cannot get this working. Here is the code: public interface IDto { } public class PaginatedDto where TDto : IDto { public int PageIndex { get; set; } public int…
tugberk
  • 57,477
  • 67
  • 243
  • 335