Suggestions for Java Generics Semantics in Java Version 7.0 - W/O Attachments

Maurizio Cimadamore Maurizio.Cimadamore at Sun.COM
Thu Jun 11 03:06:37 PDT 2009


Hi Jaisimha,
see my comments below:

Jaisimha Narahari wrote:
> I found that my previous post showed up without the attachment I'd sent, so I am posting again w/o the attachment, having transferred its contents directly into this post.
>
> It is a bit of a read, and contains also some explanations that systems guys working on JDK 7 do not really need. Because it comes from an applications developer in Bangalore 
> (I am not a systems guy). I hope you all will patiently read it. Here goes:
>
> I sincerely feel that the OO paradigm has suffered a setback with Backward Compatibility support in Java 5.0, for Raw Types in java.util.Collections of Previous Java Versions.
>
> Especially the sacrifices made w.r.t the semantics of Generics in Java 5.0 to accommodate this interoperability with Legacy Code of previous Java versions.
>
> So
> I am making suggestions for correcting the situation with Java 7.0. 
>
> I have included the arguments in favor of my suggestions.
>
> I
> definitely hope that these will be looked into, and even implemented,
> if there is no flaw in my arguments, and if bigger constraints do not
> forbid them from being incorporated into Java 7.0.
>
>  Here's hoping..  :
>
>
>
>
>
> Suggestions for
> Java Generics Semantics in Java Version 7.0
>
> It seems to me that
> in the interest of Backward Compatibility with Raw Types of
> java.util.Collections in versions previous to Java 5.0, the robustness of
> Generic Types introduced in Java 5.0 has been sacrificed.
>
> In order to make Generic Types of Java 5.0 inter-operable
> with Raw Types of java.util.Collections in versions previous to Java 5.0,
> "Erasure" has been resorted to. Erasure basically refers to the
> discarding of the type info of Type Parameters of Generic Types at runtime, so
> that a Generic Type at run time is identified only by its Base Type. 
>
> This means, for example, that a variable declared as of type
> List<Integer> at compile time is considered merely as a variable of type “List”,
> in order that it can be assigned/ passed as argument to another variable in
> Legacy Code which is also of type” List” (A Raw Type). 
>
> Raw Types, since they discard all type checking on the type
> of their contained elements, contribute to total loss of Type Safety in Java,
> which is the very reason that java.util.Collections classes in Java 5.0 were
> made Generic.
>
> The issue here is whether interoperability with legacy code
> is a sufficient enough justification to sacrifice Type Safety, given that this
> provision has also resulted in the following two contrived rules in the
> operation of Generic Types in Java 5.0:
>
>
>
> (1)   
> For the sake of determining Type Hierarchy of
> Generic Types, the   
>         Type Parameters are not to
> be considered. That is, code such as the 
>          line below is rejected by the compiler:
>
>
>                                       
> List<Object> lo = new ArrayList<Integer>;
>   
Actually this subtyping rule is a standard sound subtyping rule between 
generic types. You might wonder why it is possible e.g. to assign an 
Integer[] to an Object[] - since that assignment is not type-safe. On 
the other hand, the JVM has a way to dynamically check the correctness 
of assignments involving array so that type-safety is always enforced at 
runtime.

On the other hand, because of erasure, given that there's no runtime 
support for generics, there's no way to write a 'generic' version of the 
arraystore check. Which means that the code above should be rejected as 
unsafe: consider the following program:

List<Integer> li = new ArrayList<Integer>();

List<Object> lo = li;
lo.add("Hello!"); //ok - adding a String to a List<Object>
Integer i = li.get(0); //ClassCastException - cannot convert String to Integer

>
>                                   even as pure OOPS principles allow an
> Integer to be recognized as an 
>                                   Object.
>
>
>                                  In Java
> 5.0 Generics, List<Object> and List<Integer> are treated as 
>
>
>                                  totally unrelated types by  the above rule, not only violating the 
>
>
>                                  purity of OOPS but also sacrificing type system robustness.
>
>  
>
>     (2)   
> As a direct consequence of the above rule, any
> kind of Array Creation 
>
>
>     involving Generic Types, such as List<E> [], List<String> [], E[], etc 
>    also get forbidden,
>   

See above - because of type-erasure there's no way fo rthe JVM to take 
into account type-parameters info when performing the arraystore routine 
- this would result in unsound assignments to be allowed by the runtime.
> on account of the fact that Arrays are "Reified" 
>    types,   implying that they carry over their full type
> info into the 
>    Runtime, and are therefore aware of the type  of their contained 
>    elements at runtime, in
> direct contrast to Generic Types, which,   
>    because of Erasure,  discard the knowledge of the type of their   contained elements (i.e., Type Parameters) and are therefore   
>   "non-reifiable" types. 
>  
>
> [However, the expression E[] can be used, (without “new” used for its
> creation), to specify an array of ANY REGULAR TYPE, not Generic Type. 
> This syntax therefore is not really one to be associated with Generic Types].
>
> Having introduced Generic Types for the very purpose of Type
> System Robustness, in the interest of Backward Compatiblity with Raw Types of
> previous Java versions, Java 5.0 is promptly losing that very advantage
> provided by Generic Types, for which they were introduced in the first place.
>
> To be fair, Java 5.0 also provides a "patch up"
> API in the classes provided by java.util.Collections.checkedXXX classes, which
> try to reverse the effects of Erasure by carrying over the type info of Type
> Parameters of Generic Types also into the runtime, by separately providing
> reflection ".class" types of the Type Parameters as part of the
> checkedXXX classes.
>
> While this provision re-ensures type safety w.r.t. its loss
> due to erasure, there is no compensation concerning the above two
> "makeshift" rules that end up greatly restricting Java from having a
> very robust, elegant Type System, wherein Parameterized Types could enjoy the
> same status as any other type, without getting quirks and twists in their usage
> imposed upon them.
>
> The evolution of a programming language should not forever
> be constrained by the sins of its past versions, which in this case translates
> to the existence of Raw Types, and consequent necessity to inter-operate with
> Legacy Code making use of these Raw Types.
>
> Therefore, in the interest of Type System Robustness (which
> seems to me to be of higher priority in the longer term, in comparison to any
> immediate need for Backward Compatibility which constricts the language from
> breaking the "mold" to make true progress), I would like to  put forward these suggestions:
>
> From Java Version 7.0, going forward:
>
>                   (1) "Deprecate" Raw Types 
>
>                   (2) Remove Backward
> Compatibility provision and therefore convert 
>
>
>                        "Erasure" to
> "Reification"  for Generic Types, the
> consequence of which 
>
>
>                          will render the above two rules for the usage of Generic Types 
>                         unnecessary,
> making all types provided by the language behave 
>
>
>                         uniformly, most especially  without violating OOP
> principles in what is 
>                         essentially an OOP Language.
>
>  
>   
As you might know I'm a big fan of reification and I spent some time 
working on it, at both compile-time and runtime approaches. Because of 
the way in which generics were added to the language reification is now 
particularly problematic - consider the following code fragment:

List l = new ArrayList<String>();
Object o = (ArrayList<Integer>)l; //would pass with JDK5/6, would fail 
with reification

This is a serious source and behavioral incompatibility that might 
affect a lot of users. This is just an example of the subtle problems 
that might arise when reification support is added to the language.

But it's not just about plain generics - among the other problems: what 
is the runtime semantics of more exotic types, like e.g. intersection 
types? Should reification support wildcards? If so, should the JVM 
runtime system implement the full subtyping algorithm described by the 
JLS? How is this going to affect decidability?
> Legacy code can still make use of JDK up to Java version 6.0
> for inter-operability, with support removed from Java 7.0.
>
> An important point to note in this regard is that Java will
> continue to violate OO principles (at least according to OO purists) by having
> a single root super class called "Object" for all of its types, both
> related types and unrelated types.
>
> This has in fact been responsible for type mismatches in
> code leading to both compile time and runtime errors such as
> ClassCastException, ArrayStoreException, etc.
>
> This provision introduced from Java's inception is ARGUABLY
> a REQUIRED VIOLATION of OO in the interests of pragmatism, and has served its
> purpose well, just as similar violations of OO Principles in the implementation
> of "Enums" in Java 5.0 are (maybe) REQUIRED for similar pragmatic
> reasons.
>
> It will rock the foundations of Java's API to try and have
> separate class hierarchies for unrelated types, and so the single super class
> "Object" for all types will have to remain.
>
> Enums and their implementation have only furthered the
> interests of Type Safety.  Violations of
> OO in the internal implementation of Enums is based upon straitjacket
> constraints that must be applied to what can be allowed in the developer's
> domain, with the system enforcing a good portion of the behavior of Enums to
> make them work. Allowing full OO programming freedom with Enums to developers would
> have implied unworkable language semantics.
>
> Therefore the nearest thing to "ideal" OO that
> Java can now achieve in practice, is with the implementation of  the above two suggestions in Java 7.0. Java
> must only then continue to evolve from there.
>
> Thanks for your patience.
>
>
>
>
>   
Thanks
Maurizio



More information about the jdk7-dev mailing list