Covariance and contravariance (computer science): Difference between revisions

Content deleted Content added
Remove duplicate references, use {{rp}} instead. Fixed citation formatting and added author name. Added more inline citations.
Remove duplicate citations.
Line 64:
For instance, in Java {{java|String[]}} is a subtype of {{java|Object[]}}, and in C# {{C sharp|string[]}} is a subtype of {{C sharp|object[]}}.
 
As discussed above, covariant arrays lead to problems with writes into the array. Java<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|126}} and C# deal with this by marking each array object with a type when it is created. Each time a value is stored into an array, the execution environment will check that the run-time type of the value is equal to the run-time type of the array. If there is a mismatch, an {{java|ArrayStoreException}} (Java)<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|126}} or {{C sharp|ArrayTypeMismatchException}} (C#) is thrown:
 
<syntaxhighlight lang="java">
Line 83:
One drawback to this approach is that it leaves the possibility of a run-time error that a stricter type system could have caught at compile-time. Also, it hurts performance because each write into an array requires an additional run-time check.
 
With the addition of generics, Java<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|126-129}} and C# now offer ways to write this kind of polymorphic function without relying on covariance. The array comparison and shuffling functions can be given the parameterized types
 
<syntaxhighlight lang="java">
Line 428:
Use-site variance means the desired variance is indicated with an annotation at the specific site in the code where the type will be used. This gives users of a class more opportunities for subtyping without requiring the designer of the class to define multiple interfaces with different variance. Instead, at the point a generic type is instantiated to an actual parameterized type, the programmer can indicate that only a subset of its methods will be used. In effect, each definition of a generic class also makes available interfaces for the covariant and contravariant ''parts'' of that class.
 
Java provides use-site variance annotations through [[Wildcard (Java)|wildcards]], a restricted form of [[bounded quantification|bounded]] [[existential type]]s. A parameterized type can be instantiated by a wildcard {{java|?}} together with an upper or lower bound, e.g. {{java|List<? extends Animal>}} or {{java|List<? super Animal>}}. An unbounded wildcard like {{java|List<?>}} is equivalent to {{java|List<? extends Object>}}. Such a type represents {{java|List<X>}} for some unknown type {{java|X}} which satisfies the bound.<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|139}} For example, if {{java|l}} has type {{java|List<? extends Animal>}}, then the type checker will accept
 
<syntaxhighlight lang="java">
Line 444:
[[File:Java wildcard subtyping.svg|thumb|right|350px|Wildcard subtyping in Java can be visualized as a cube.]]
 
While non-wildcard parameterized types in Java are invariant (e.g. there is no subtyping relationship between {{java|List<Cat>}} and {{java|List<Animal>}}), wildcard types can be made more specific by specifying a tighter bound. For example, {{java|List<? extends Cat>}} is a subtype of {{java|List<? extends Animal>}}. This shows that wildcard types are ''covariant in their upper bounds'' (and also ''contravariant in their lower bounds''). In total, given a wildcard type like {{java|C<? extends T>}}, there are three ways to form a subtype: by specializing the class {{java|C}}, by specifying a tighter bound {{java|T}}, or by replacing the wildcard {{java|?}} with a specific type (see figure).<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|139}}
 
By applying two of the above three forms of subtyping, it becomes possible to, for example, pass an argument of type {{java|List<Cat>}} to a method expecting a {{java|List<? extends Animal>}}. This is the kind of expressiveness that results from covariant interface types. The type {{java|List<? extends Animal>}} acts as an interface type containing only the covariant methods of {{java|List<T>}}, but the implementer of {{java|List<T>}} did not have to define it ahead of time.
 
In the common case of a generic data structure {{C sharp|IList}}, covariant parameters are used for methods getting data out of the structure, and contravariant parameters for methods putting data into the structure. The mnemonic for Producer Extends, Consumer Super (PECS), from the book ''Effective Java'' by [[Joshua Bloch]] gives an easy way to remember when to use covariance and contravariance.<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|141}}
 
Wildcards are flexible, but there is a drawback. While use-site variance means that API designers need not consider variance of type parameters to interfaces, they must often instead use more complicated method signatures. A common example involves the {{Javadoc:SE|java/lang|Comparable}} interface.<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|66}} Suppose we want to write a function that finds the biggest element in a collection. The elements need to implement the {{java|compareTo}} method<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|66}}, so a first try might be
 
<syntaxhighlight lang="java">