-
-
Save tedyoung/aca78496d424790bb0f19d36a4618f76 to your computer and use it in GitHub Desktop.
Demonstrates the concepts of covariance and contravariance in the Java type system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
/* | |
* Covariance and contravariance. | |
* | |
* A type operator (an operator which takes as input a type and returns another type as output) is | |
* said to be | |
* 1) `covariant` if it preserves the ordering of types and orders types | |
* from more specific ones to more generic ones. | |
* 2) `contravariant` if it preserves the ordering of types and orders types | |
* from more generic ones to more specific ones. | |
* 3) `invariant` if no ordering of types is preserved. | |
* | |
* Example of covariance: | |
* String <= Object (`<=` means lhs is more specific than rhs). | |
* and String[] <= Object[] (hence array operator [] is covariant in Java). | |
* | |
* Example of invariance: | |
* String <= Object | |
* and List<String> =/= List<Object> (no ordering is preserved in generic types in Java hence invariant). | |
* | |
* Why would you care about covariance and contravariance while programming? Answer: "substitutability". | |
* For instance if a Java generic type was covariant, you can subsitute a more specific generic type | |
* in place of a more generic generic type. | |
* Example: | |
* List<Object> = someObj.someMethod(); // someObj.someMethod returns List<String> | |
* | |
* Similarly if a Java generic type was contravariant, you can substitute a more generic generic type | |
* in place of a more specific generic type. | |
* Example: | |
* someObj.someMethod(List<Object>); // someMethod expects List<String> as argument | |
* | |
* Arrays in Java and C# are covariant by design. This would be fine if arrays were | |
* immutable (ie only supported get() operation). But arrays are mutable in Java and C# (ie) | |
* they support reading/get() and writing/set() elems in the array. | |
* | |
* Example: | |
* String[] a = new String[1]; | |
* Object[] b = a; | |
* Object o = b[0]; // get(0) does not break type-safety | |
* b[0] = 1; // set(0) will break type-safety (raises runtime error). | |
* | |
* In order to ensure type-safety, either arrays should be made "immutable and covariant" or "mutable and invariant". | |
* | |
* Generic types both in C# and Java are invariant by default. In C#4.0, they're adding support so that generic types | |
* can be made covariant and contravariant as necessary provided the generic interfaces obey certain rules. | |
* | |
* Read more: | |
* http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) | |
* http://etymon.blogspot.com/2007/02/java-generics-and-covariance-and.html | |
* http://acodingfool.typepad.com/blog/2009/02/the-new-and-improved-csharp-40-part-2.html | |
* | |
*/ | |
public class CovarianceTest { | |
public static void main(String[] args) { | |
// allowed | |
String s1 = "foobar"; | |
Object o1 = s1; | |
// allowed | |
// but breaks type-safety (read above for explanation) | |
String[] arr1 = new String[2]; | |
Object[] arr2 = arr1; | |
// allowed | |
ArrayList<String> al1 = new ArrayList<String>(); | |
List<String> l1 = al1; | |
l1.add(new String("foo")); | |
// not allowed | |
// ArrayList<Object> al2 = al1; | |
// allowed - generics with wildcard ? | |
ArrayList<?> al3 = al1; | |
Object o2 = al3.get(0); | |
// not allowed | |
// al3.add(new String("foo")); | |
// allowed - generics with wildcard extends | |
List<Integer> l2 = new ArrayList<Integer>(); | |
List<? extends Number> l3 = l2; | |
Number n1 = l3.get(0); | |
// not allowed | |
// l3.add(new Integer(1)); | |
// allowed - generics with wildcard super | |
List<Number> l4 = new ArrayList<Number>(); | |
List<? super Integer> l5 = l4; | |
l5.add(new Integer(1)); | |
// not allowed | |
// Number n2 = l5.get(0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment