Covariance

From APIDesign

Revision as of 15:32, 14 July 2016 by JaroslavTulach (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

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