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
8
votes
1 answer

Is there a way to type a TypeScript method decorator to restrict the type of the method it can decorate?

I want to write a TypeScript method decorator that can only be applied to methods with a certain type of first argument. It's a common pattern in the codebase I'm working in to pass around a request context that has handles for database, metrics,…
8
votes
17 answers

Why doesn't inheritance work the way I think it should work?

I'm having some inheritance issues as I've got a group of inter-related abstract classes that need to all be overridden together to create a client implementation. Ideally I would like to do something like the following: abstract class Animal { …
Luke
  • 18,585
  • 24
  • 87
  • 110
8
votes
1 answer

Can I have a type that's both, covariant and contravariant, i.e. fully fungible/changeable with sub and super types?

Can I have a type (for now forgetting its semantics) that can be covariant as well as contravariant? for example: public interface Foo { void DoFooWith(T arg); } Off to Eric Lippert's blog for the meat and potatoes of variance in C#…
Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
8
votes
2 answers

Covariance and Contravariance inference in C# 4.0

When we define our interfaces in C# 4.0, we are allowed to mark each of the generic parameters as in or out. If we try to set a generic parameter as out and that'd lead to a problem, the compiler raises an error, not allowing us to do…
devoured elysium
  • 101,373
  • 131
  • 340
  • 557
8
votes
1 answer

c# compiler error 'Parameter must be input safe. Invalid variance. The type parameter 'T' must be invariantly valid on Expression '

I want to use my interface co-variantly (Interface must be co-variant) but the Compiler give me error c# compiler error:- 'Parameter must be input safe. Invalid variance. The type parameter 'T' must be invariantly valid on 'Expression' This is my…
yo2011
  • 971
  • 2
  • 12
  • 38
8
votes
1 answer

VB.NET Implement Multiple Contravariant interface types

Basic Question: Given an interface: ICopiesFrom(Of In TModel) where there is no type constraint on the generic argument, can that interface be implemented more than once on the same concrete type using a different type argument without a compiler…
xDaevax
  • 2,012
  • 2
  • 25
  • 36
8
votes
1 answer

Contravariance in Expressions

I'm trying to create a Generic Action Delegate delegate void ActionPredicate(T1 t1, T2 t2); and public static ActionPredicate GetSetterAction(string fieldName) { ParameterExpression targetExpr =…
kans
  • 225
  • 2
  • 8
7
votes
3 answers

Method overload resolution and generic/contravariant interfaces in C#

I think my problem is best explained with a code snippet of my class/interface-hierarchy: public interface ITransform // or --> seems to make no difference here { void Transform(D data); } interface ISelection {} interface IValue :…
Stephan
  • 185
  • 2
  • 6
7
votes
1 answer

How to add an apple delegate to a list of fruit delegates?

I have a sample program with a base Fruit class and a derived Apple class. class Testy { public delegate void FruitDelegate(T o) where T : Fruit; private List> fruits = new List>(); public…
Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
7
votes
4 answers

covariance/contravariance in C#

I have a book that explains contravariance/covariance as follows : a delegate can have more specific parameter types than its method target. This is called contravariance the return type of a delegate can be less specific than the return type of…
prosseek
  • 182,215
  • 215
  • 566
  • 871
7
votes
2 answers

Does covariance/contravariance apply to implicitly convertable types that don't implement a common interface?

I'm currently reading up on Covariance and Contravariance in C#. All examples have details of objects being convertable and differ because of the accuracy from the Interface implementation e.g. Where Circle : IShape Covariance: SomeType as…
StuperUser
  • 10,555
  • 13
  • 78
  • 137
7
votes
3 answers

Invariant inheritance problem

I'm trying to implement a strategy pattern to allow me to allow me to apply some "benefit" to an "account". In the code below, I can't add my implementation of an interface to a dictionary expecting the interface. I think it's some kind of…
scottm
  • 27,829
  • 22
  • 107
  • 159
7
votes
1 answer

Error: Covariant type A occurs in contravariant position

I was trying to write an immutable Matrix[A] class. I want the class to be covariant on A but when I put + in front of A compiler starts complaining about some operations in the class. Following is a relevant subset of my Matrix class (The actual…
assasin95
  • 71
  • 1
  • 3
7
votes
3 answers

Type inference with piping or composition fails, where normal function call succeeds

I rarely have this struggle nowadays with F#, but then again type inheritance is much less common with F#, so perhaps I was just lucky. Or I am missing the obvious. Normally when the compiler complains about not knowing a certain type I reverse the…
Abel
  • 56,041
  • 24
  • 146
  • 247
7
votes
2 answers

Why does C# use contravariance (not covariance) in input parameters with delegate?

When we have a Base class that inherits BBase and a Derived class that specializes it, let's say there is a delegate that requires Base as an input. using System; class BBase {} class Base : BBase {} class Derived : Base {} delegate void…
prosseek
  • 182,215
  • 215
  • 566
  • 871