JaroslavTulach: /* Generics, Covariance and Contravariance */ - 2014-06-25 07:53:44

Generics, Covariance and Contravariance

←Older revision Revision as of 07:53, 25 June 2014
Line 52: Line 52:
== Generics, Covariance and Contravariance ==
== Generics, Covariance and Contravariance ==
-
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 [[wikipedia:Type_erasure|erasure]] of generic type information in [[Java]] one can use both-variances to own benefits.
+
It is well known that while [[Covariance]] and [[Contravariance]] work OK from the source compatibility point of view in [[Java]], 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 [[wikipedia:Type_erasure|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:
Imagine there is a simple method that operates on set of integers:

JaroslavTulach at 12:33, 24 June 2012 - 2012-06-24 12:33:10

←Older revision Revision as of 12:33, 24 June 2012
Line 73: Line 73:
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
-
PS: Tribute goes to [[User:Cordeo|Rino Kadijk]] for discovering the change is functionally incompatible, as it can be differentiated using reflection on parameter types of the '''arePositive''' method
+
PS: Tribute goes to [[User:Cordeo|Rijk van Haaften]] for discovering the change is functionally incompatible, as it can be differentiated using reflection on parameter types of the '''arePositive''' method

JaroslavTulach at 12:31, 24 June 2012 - 2012-06-24 12:31:54

←Older revision Revision as of 12:31, 24 June 2012
Line 73: Line 73:
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
-
PS: Tribute goes to [[Cordeo|Rino Kadijk]] for discovering the change is functionally incompatible, as it can be differentiated using reflection on parameter types of the '''arePositive''' method
+
PS: Tribute goes to [[User:Cordeo|Rino Kadijk]] for discovering the change is functionally incompatible, as it can be differentiated using reflection on parameter types of the '''arePositive''' method

JaroslavTulach at 12:30, 24 June 2012 - 2012-06-24 12:30:49

←Older revision Revision as of 12:30, 24 June 2012
Line 73: Line 73:
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
PS: Tribute for this inventive use of generic type [[erasure]] belongs to Tomáš Zezula.
 +
PS: Tribute goes to [[Cordeo|Rino Kadijk]] for discovering the change is functionally incompatible, as it can be differentiated using reflection on parameter types of the '''arePositive''' method

JaroslavTulach: /* The Erasure Doublethink */ - 2012-06-24 12:26:17

The Erasure Doublethink

←Older revision Revision as of 12:26, 24 June 2012
Line 34: Line 34:
</source>
</source>
-
The type variable T of class Node (see the tutorial of Oracle) is indeed erased. But the compiler does not erase information about generics from subclass declarations. So after type erasure, the class MyNode actually becomes:
+
The type variable T of class Node (see the tutorial of Oracle) is indeed erased on all instances. Given an instance of Node, one cannot, during runtime find out what is the actual type parameter. But the compiler does not erase information about generics from subclass declarations. So after type erasure, the class MyNode actually becomes:
<source lang="java">
<source lang="java">
public class MyNode extends Node<Integer> {
public class MyNode extends Node<Integer> {
Line 47: Line 47:
The type parameter Integer is present in Mynode.class and can be retrieved at runtime using reflection. The same is true for method signatures.
The type parameter Integer is present in Mynode.class and can be retrieved at runtime using reflection. The same is true for method signatures.
<source lang="java" snippet="variance.erasure.v1"/>
<source lang="java" snippet="variance.erasure.v1"/>
-
The type parameter Integer (strictly: ? extends Integer) of arePositive is available at runtime. So if it is changed to Number, the JVM can see the type parameter is now Number.
+
The type parameter Integer (strictly: ? extends Integer) of arePositive is available at runtime. So if it is changed to Number, the reflection and the [[JavaC]] can see the type parameter is now Number. However the [[JVM]] does not care, it operates on the raw types only and thus it sees only {{JDK|java/util|Set}}:
<source lang="java" snippet="variance.erasure.v2"/>
<source lang="java" snippet="variance.erasure.v2"/>

JaroslavTulach at 12:20, 24 June 2012 - 2012-06-24 12:20:28

←Older revision Revision as of 12:20, 24 June 2012
Line 9: Line 9:
</source>
</source>
-
On the other hand, the compiler needs the generics information in [[API]]s people compile against. It needs to know {{JDK|java/util|List}} has one type parameter. As a result the things with [[erasure]] of generics are quite complex. The generic types are not there from the point of [[JVM]] and are there from the point of view of [[JavaC]].
+
On the other hand, the compiler needs the generics information in [[API]]s people compile against. It needs to know {{JDK|java/util|List}} has one type parameter. As a result the things with [[erasure]] of generics are quite complex. The generic types are not there from the point of [[JVM]] but are present from the point of view of [[JavaC]] and reflection.
== The [[Erasure]] [[Doublethink]] ==
== The [[Erasure]] [[Doublethink]] ==

JaroslavTulach at 12:19, 24 June 2012 - 2012-06-24 12:19:03

←Older revision Revision as of 12:19, 24 June 2012
Line 1: Line 1:
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just {{JDK|java/util|List}}. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just {{JDK|java/util|List}}. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
-
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just the raw class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
+
The designers of the [[Java]] language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just the raw class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
<source lang="java">
<source lang="java">

JaroslavTulach at 11:50, 24 June 2012 - 2012-06-24 11:50:52

←Older revision Revision as of 11:50, 24 June 2012
Line 1: Line 1:
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just {{JDK|java/util|List}}. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just {{JDK|java/util|List}}. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
-
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just one class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
+
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just the raw class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
<source lang="java">
<source lang="java">

JaroslavTulach at 11:49, 24 June 2012 - 2012-06-24 11:49:58

←Older revision Revision as of 11:49, 24 June 2012
Line 1: Line 1:
-
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just List. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
+
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just {{JDK|java/util|List}}. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just one class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just one class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.

JaroslavTulach at 11:49, 24 June 2012 - 2012-06-24 11:49:34

←Older revision Revision as of 11:49, 24 June 2012
Line 1: Line 1:
-
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example List<Integer> rather than just List. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
+
Generics were added to the [[Java]] language to improve compile time type checking. Generics make it possible to specify the element type of collections. For example {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> rather than just List. This allows the compiler to differentiate between {{JDK|java/util|List}}<{{JDK|java/lang|Integer}}> and {{JDK|java/util|List}}<{{JDK|java/lang|String}}>, so the compiler can prevent the programmer from adding an element of the wrong type to the list.
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just one class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.
The designers of the Java language wanted the language change to be [[BackwardCompatibility|backward compatible]] as much as possible. So using just {{JDK|java/util|List}} is still allowed. Also the goal was to minimize changes in the [[HotSpot]] [[JVM]]. In order to achieve this, the compiler erases the element type from objects on the heap and uses just one class for all instantiations. For example {{JDK|java/util|ArrayList}} is used for both {{JDK|java/util|ArrayList}}<String> and {{JDK|java/util|ArrayList}}<Integer>.