Erasure
From APIDesign
Line 13: | Line 13: | ||
<source lang="java" snippet="variance.erasure.v2"/> | <source lang="java" snippet="variance.erasure.v2"/> | ||
- | Obviously, this is source compatible as this is [[Contravariance|contravariant]] extension of the range of values the method can absorb. Surprising (at least for those who remember that [[Contravariance]] is not binary compatible) is that this change is also binary compatible - e.g. it is fully [[BackwardCompatible]]! The is caused by the [[Erasure]] of generic type information. When compiled into binary form, the signature method is just {{JDK|java/util|Set}} (without any additional generic information), so the [[JVM]] sees no change between version 1.0 of the API and version 2.0. Both work on {{JDK|java/util|Set}}s. | + | Obviously, this is [[SourceCompatibility|source compatible]] as this is [[Contravariance|contravariant]] extension of the range of values the method can absorb. Without a doubt this is also [[FunctionalCompatibility|functionally compatible]], as the code now calls '''doubleValue''' method and this one was available on {{JDK|java/lang|Integer}}s as well, so there is no change in the runtime contract. |
+ | |||
+ | The only question is whether code compiled against old [[API]] will link against new [[API]]? Surprising (at least for those who remember that [[Contravariance]] is not [[BinaryCompatibility|binary compatible]]) is that this change is also binary compatible - e.g. it is fully [[BackwardCompatible]]! The is caused by the [[Erasure]] of generic type information. When compiled into binary form, the signature method is just {{JDK|java/util|Set}} (without any additional generic information), so the [[JVM]] sees no change between version 1.0 of the API and version 2.0. Both work on {{JDK|java/util|Set}}s. |
Revision as of 18:14, 19 October 2011
It is well known that while Covariance and Contravariance work OK from the source compatibility point of view in Java, but they are not very BackwardCompatible from the binary point of view. As the binary compatibility is one of the most important ones for a compiled language like Java, one could think, that usage of Covariance or Contravariance is impossible. However it is not (at least not completely) - with the help of erasure of generic type information in Java one can use both-variances to own benefits.
Imagine there is a simple method that operates on set of integers:
Code from Erasure.java:
See the whole file.public static boolean arePositive(Collection<? extends Integer> numbers) { for (Integer n : numbers) { if (n <= 0) { return false; } } return true; }
Any user of such API can call this method with a set of Integers:
Code from ErasureTest.java:
See the whole file.List<Integer> oneToTen = Arrays.asList(2, 4, 6, 8, 10); boolean positive = arePositive(oneToTen); System.err.println("positive = " + positive); assert positive : "All the numbers are positive: " + oneToTen;
Later somebody decides that it would be nice to change method to accept not only integers, but all numbers and creates new version of the API with the same method, but accepting wider parameter types:
Code from Erasure.java:
See the whole file.public static boolean arePositive(Collection<? extends Number> numbers) { for (Number n : numbers) { if (n.doubleValue() <= 0.0d) { return false; } } return true; }
Obviously, this is source compatible as this is contravariant extension of the range of values the method can absorb. Without a doubt this is also functionally compatible, as the code now calls doubleValue method and this one was available on Integers as well, so there is no change in the runtime contract.
The only question is whether code compiled against old API will link against new API? Surprising (at least for those who remember that Contravariance is not binary compatible) is that this change is also binary compatible - e.g. it is fully BackwardCompatible! The is caused by the Erasure of generic type information. When compiled into binary form, the signature method is just Set (without any additional generic information), so the JVM sees no change between version 1.0 of the API and version 2.0. Both work on Sets.