Covariance

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(New page: Everything one would ever like to know about Covariance and Contravariance is available at wikipedia. Here is just a ...)
Line 1: Line 1:
-
Everything one would ever like to know about [[Covariance]] and [[Contravariance]] is available at [[wikipedia:Covariance_and_contravariance_(computer_science)|wikipedia]]. Here is just a small example how it does not work in [[Java]].
+
Everything one would ever like to know about [[Covariance]] and [[Contravariance]] is available at [[wikipedia:Covariance_and_contravariance_(computer_science)|wikipedia]]. Here is just a small example to show how it does not work in [[Java]].
Imagine simple program that computes maximum from two integers:
Imagine simple program that computes maximum from two integers:
Line 5: Line 5:
<source lang="java" snippet="variance.covariance.v1"/>
<source lang="java" snippet="variance.covariance.v1"/>
-
due to mistake the version 1.0 of the program does not return an {{JDK|java/lang|Integer}}, but rather its super type {{JDK|java/lang|Number}}. Such return type can still be used to perform some useful operations, but it is cumbersome:
+
due to a mistake the version 1.0 of the program does not return an {{JDK|java/lang|Integer}}, but rather its super type {{JDK|java/lang|Number}}. This is not a complete mistake, even plain {{JDK|java/lang|Number}} can be useful, but its usage is a bit cumbersome. One needs to convert it to '''int''' first:
<source lang="java" snippet="variance.covariance.test"/>
<source lang="java" snippet="variance.covariance.test"/>
-
Thus in version 2.0 the author of the [[API]] may decide to fix the type to {{JDK|java/lang|Integer}}:
+
Now imagine that the author of the [[API]] decides to fix the design flaw and release version 2.0 of the [[API]] where the method will return an {{JDK|java/lang|Integer}}:
<source lang="java" snippet="variance.covariance.v2"/>
<source lang="java" snippet="variance.covariance.v2"/>
-
This is a [[BackwardCompatible]] change from the source point of view. Every (reasonable) code that compiled with version 1.0 will still compile (as {{JDK|java/lang|Integer}} contains all the method one could call on {{JDK|java/lang|Number}}). However this is heavily incompatible change from the point of binary compatibility. Programs compiled against version 1.0 will not link against version 2.0 as the [[JVM]] seeks method that takes exactly one '''Number''' argument and does not do any tricks with polymorphism at all:
+
This is a fine change from the point of view of [[SourceCompatibility]]. Every ([[InstanceOf|reasonable]]) code that compiled with version 1.0 will still compile (as {{JDK|java/lang|Integer}} contains all the method one could call on {{JDK|java/lang|Number}}). However this is heavily incompatible change from the point of [[BinaryCompatibility]]. Programs compiled against version 1.0 will not link against version 2.0. Unlike [[JavaC]], the [[JVM]] seeks for the proper method using an exact match. Only method with one {{JDK|java/lang|Number}} argument needs to be present and no tricks with polymorphism can help you cheat the [[JDK]]:
<source lang="bash">
<source lang="bash">
Line 21: Line 21:
</source>
</source>
-
As a result one can use [[Covariance]] or [[Contravariance]] in [[Java]] much. Unless one relies of [[Erasure]].
+
As a result one cannot use [[Covariance]] or [[Contravariance]] in [[Java]] much. Unless one relies of on other side effects: There is a [[Erasure|larger example]] demonstrating that [[Covariance]] may work in [[Java]] undercertain circumstances.

Revision as of 17:27, 19 October 2011

Everything one would ever like to know about Covariance and Contravariance is available at wikipedia. Here is just a small example to show how it does not work in Java.

Imagine simple program that computes maximum from two integers:

Code from Covariance.java:
See the whole file.

public static Number max(int n1, int n2) {
    return Math.max(n1, n2);
}
 

due to a mistake the version 1.0 of the program does not return an Integer, but rather its super type Number. This is not a complete mistake, even plain Number can be useful, but its usage is a bit cumbersome. One needs to convert it to int first:

Code from CovarianceTest.java:
See the whole file.

public static void main(String[] args) {
    Number n = Covariance.max(10, 20);
    System.err.println("value: " + n + " type: " + n.getClass());
    assert n.intValue() == 20 : "The max should be 20, but was: " + n;
}
 

Now imagine that the author of the API decides to fix the design flaw and release version 2.0 of the API where the method will return an Integer:

Code from Covariance.java:
See the whole file.

public static Integer max(int n1, int n2) {
    return Math.max(n1, n2);
}
 

This is a fine change from the point of view of SourceCompatibility. Every (reasonable) code that compiled with version 1.0 will still compile (as Integer contains all the method one could call on Number). However this is heavily incompatible change from the point of BinaryCompatibility. Programs compiled against version 1.0 will not link against version 2.0. Unlike JavaC, the JVM seeks for the proper method using an exact match. Only method with one Number argument needs to be present and no tricks with polymorphism can help you cheat the JDK:

Mixing does not work: Compiling against version 1.0 and running against version 2.0 of the API fails:
Exception in thread "main" java.lang.NoSuchMethodError: api.Covariance.max(II)Ljava/lang/Number;
	at test.CovarianceTest.main(Unknown Source)

As a result one cannot use Covariance or Contravariance in Java much. Unless one relies of on other side effects: There is a larger example demonstrating that Covariance may work in Java undercertain circumstances.

Personal tools
buy