Covariance and contravariance (computer science): Difference between revisions

Content deleted Content added
m Grammar and punctuation fixes
m rv grammar regressions
Line 11:
A programming language designer will consider variance when devising [[typing rule]]s for language features such as [[Array (data type)|array]]s, [[Inheritance (object-oriented programming)|inheritance]], and [[generic datatype]]s. By making type constructors covariant or contravariant instead of '''invariant''', more programs will be accepted as well-typed. On the other hand, programmers often find contravariance unintuitive, and accurately tracking variance to avoid [[runtime errors|runtime type errors]] can lead to complex typing rules.
 
In order to keep the type system simple and allow useful programs, a language may treat a type constructor as invariant even if it would be safe to consider it variant, or treat it as covariant even though that could violate type safety.
 
== Formal definition ==
Line 30:
* {{C sharp|Action<Animal>}} is a subtype of {{C sharp|Action<Cat>}}. The subtyping is reversed because {{C sharp|Action<T>}} is '''contravariant''' on {{C sharp|T}}.
* Neither {{C sharp|IList<Cat>}} nor {{C sharp|IList<Animal>}} is a subtype of the other, because {{C sharp|IList<T>}} is '''invariant''' on {{C sharp|T}}.
The variance of a C# generic interface is declared by placing the {{C sharp|out}} (covariant) or {{C sharp|in}} (contravariant) attribute on (zero or more of) its type parameters.<ref name=Skeet>{{cite book |last=Skeet|first=Jon|title= C# in Depth |date=23 March 2019 |publisher= Manning |isbn= 978-1617294532}}</ref>{{rp|144}} The above interfaces are declared as {{C sharp|IEnumerable<out T>}}, {{C sharp|Action<in T>}}, and {{C sharp|IList<T>}}. Types with more than one type parameter may specify different variances on each type parameter. For example, the delegate type {{C sharp|Func<in T, out TResult>}} represents a function with a '''contravariant''' input parameter of type {{C sharp|T}} and a '''covariant''' return value of type {{C sharp|TResult}}.<ref>[http://msdn.microsoft.com/en-us/library/bb549151.aspx Func<T, TResult> Delegate] - MSDN Documentation</ref><ref name=Skeet />{{rp|145}} The compiler checks that all types are defined and used consistently with their annotations, and otherwise signals a compilation error.
 
The [[#Interfaces|typing rules for interface variance]] ensure type safety. For example, an {{C sharp|Action<T>}} represents a first-class function expecting an argument of type {{C sharp|T}},<ref name=Skeet />{{rp|144}} and a function that can handle any type of animal can always be used instead of one that can only handle cats.