Summary
Generics in Java are currently implemented using erasure: type parameters are removed from generic types at runtime. Reified generic type parameters, by contrast, are available to the JVM at runtime. Neal Gafter explains in a recent blog post how reified generic types might be implemented.
Advertisement
In a recent blog post, Reified Generics for Java, Neal Gafter describes the limitations of the current, erasure-based generics implementation in Java:
Generics are implemented using erasure, in which generic type parameters are simply removed at runtime. That doesn't render generics useless, because you get typechecking at compile-time based on the generic type parameters, and also because the compiler inserts casts in the code (so that you don't have to) based on the type parameters...
For a type parameter T, you can't write a class literal T.class. You can't use instanceof to test if an object is of type T. And you can't create an array of T...
But it gets worse. You also can't write class literals for generic types like List<String>.class, or test if an object is an instanceof List<String>, or create an array of List<String>. The implementation of generics using erasure also causes Java to have unchecked operations, which are operations that would normally check something at runtime but can't do so because not enough information is available. For example, a cast to the type List<String> is an unchecked cast, because the generated code checks that the object is a List but doesn't check whether it is the right kind of list.
Gafter explains that the reason generics were implemented this way had to do with the need to preserve backward compatibility with existing code that did not use generics. He then proposes two ways to add reified generics to Java:
It isn't too late to add reified generics to Java. There are two basic approaches. The first uses the language as it exists today but adds the generic type information at runtime. In the ideal world, we wait until every bit of Java code in the world has been modified to use generics safely, and then go through a transition in which we start recording type parameters at runtime by using a new javac and VM. There are two main difficulties with this approach. First, it is not compatible... The second problem is more insidious: lots of existing code uses generics but uses them in an unsafe way. For example, I have seen code that creates an ArrayList<Object>, but later casts it to a List<String> where the author knows that it only contains objects of type String. I would not be surprised to find such code in the JDK. Such code must fail at runtime when generics are reified, so some existing (but working) code would be broken...
The other approach modifies the language so that the declaration of a generic parameter distinguishes reified type parameters from erased ones. It is a pure extension of the language. The existing syntax for generics would continue to designate generics by type erasure, but a newly introduced syntax would be used to declare reified type parameters...
With the latter approach, Gafter envisions a new, reified implementation of collections. New code could reference the reified collection implementation, while old code using the erasure-based implementation would not break.
The problem with Generics is the mistakes made in the original Java design. Generics should be incorporated from the start of a language design. So as the desingers try to correct these oversights, they have to keep kludging up the language to keep it compatible with old code.
Personally, I think it's time for Java to clean house and come out with a Java 2.0 (the version numbering scheme is another mess they've made. 1.5 == 5.0 ???)
Break compatibility. Clean up and the APIs focusing on re-simplification. The ideas that Neil Gafter proposes could be used without trying to mix-in these new features into an already confused spec.
> > Generics is already complicated enough - as it is. > > Arnold: "Generics are a mistake. ..."
And most comments on Arnold's blog say how great generics are ...
No, generics are not fundamentally wrong. It's Sun's reluctance to embrace generics fully and properly that is the fundamental problem: a) It should have been parametrised, not generic, classes. Why? We sometimes need more than types to parametrise a class, e.g., an integer as in Array<T,rank> b) Erasure is wrong. c) T[] ... is wrong. It should be Array<T> ... . This is a subtle but important distinction. d) Self-referential generics are not a problem but a fundamental requirement for proper implementation. See e.g., http://www.jot.fm/issues/issue_2002_05/column5 and subsequent articles (not easy reading but necessary for a foundation in templates/generics/...).
"For a type parameter T, you can't write a class literal T.class. You can't use instanceof to test if an object is of type T. And you can't create an array of T..."
The few times I've wanted to do this, I added a Class parameter to the constructor and saved it. A bit klunky, but it works. For example, I wanted to be able to construct a new T from an array of Integers(somewhat terse and sketchy code with no error handling)
class MiracleBuilder<T> {
private Class mClass;
public MiracleBuilder(Class clazz) { mClass = class; }
public T buildFromIntegers(Integer[] ints) { Class[] argClass = new Class[ints.length]; for (int i=0; i<argClass.length; i++) argClass[i] = Integer.class;
There seems to be a consensus around that Java has lost it's 'freshness', and is being stretched too far. Isn't it time to respect the Java language for what it is (and it's served me very well in the past), and move on to new languages now like JRuby/Groovy/Scala if you want anything more without losing the advantage of the JVM and old Java libraries.
All this recent development of Java, and talk about closures etc, has the feel of beating out an extra few miles from a weary old horse. Poor thing.
> There seems to be a consensus around that Java has lost > it's 'freshness', and is being stretched too far. What is being stretched too far is 1) the non-removal of old JDK code 2) the stupid insistance not to introduce new, elegant syntax
For example, for(item : list) was taken instead of foreach(item in list). The usual answer is that foreach and in might have been used as indentifiers - although certainly not in that exact form. So in the sake of compatability, why not make them context sensitive keywords, like MS did in the last edition of VC++?
> Isn't it time to respect the Java language for what it is The vast amount of Java libraries are both Java's most valuable asset and it's millstone round it's neck. That's what caused the brain twisting type erasure.
> and move on to new languages why not make a new language "Java7" and say "it's just another version of Java". Sure, it might be confusing on a technical level, but it will gain traction much faster than any of Scala/Groovy/etc. (which I think don't qualify for Java7, but that's another thread). It's important that the new language has more or less the same style and that the JDK is rewritten to match the flavor of the new language. And there must not be new releases of the old Java. There are examples where it has been done, and I think it worked: EJB3, VB.NET, probably others
The critical issue is that there is an acceptable migration path, NOT to be absolutely backwards compatible.
When the mainstream paradigm shifted to OO, C wasn't extended to cope with that. C++ and Java appeared. I'm glad C is still there in pretty much its original form if ever I need it for the class of small/fast systems where it's ideal.
The same is true of Java. Now that there's another shift happening it'd be saner to just let Java be. And losing backwards compatibility would be a practical disaster.
I'm quite envious of people like Bruce Eckel escaping Java-land and finding Python. Bet he's having fun! I wish there was a way for me to do that safely without having to ditch the JVM. My ideal would be for Sun to put real resources behind a synthesis of the best aspects Scala/Groovy/JRuby/etc and support it as an equal of Java. I can dream.
My response can be read in my blog at <a href="javecua.blogspot.com">javecua.blogspot.com</a>. In some sense, you could be right, i.e. if folks on sun want to hold backward compatibility forever. But I see Java still as a fresh programming language.
I think if you review the history of C++ you'll find that the first implementations were based on cfront which was at it's essence a fancy macro'ing of C to provide the C++ syntax. So I would say that C was extended.
Closures should have been in the langauge from the beginning. However I've always seen Java as a bridge between OO languages such as Smalltalk and functional languages such as C++. IOWs, it got us halfway there. Pure speculation but my guess is that having features such as closures from the get go would have slowed Java's adoption. The only evidence that I'll put forth in support is the trouble that Cobol programmers who were converting to Smalltalk in the mid-90s were having with the feature in that langauge. That said, the syntax and "thinking in Smalltalk" is much farther away from Cobol than C/C++ is so many of these developers were having lots of trouble adapting.
> Pure speculation but my guess is that having features such > as closures from the get go would have slowed Java's > adoption.
I don't think so, Kirk. I personally had to make the shift from procedural to OO/Java in the late 90s, and on more than one occasion I've tried to teach Java and OO programming to COBOL (and other procedural language) programmers. My experience is that the mind shift required to 'think in OO' is so hard that adding closures on top wouldn't make that much difference to the adoption rate.
Well, my experience has also been that most procedural programmers would rather be boiled in oil than make the change, and most of them who are trying are doing so only because of management fiat. Again in this case adding on 5% more syntactic sugar wouldn't be a factor.
I will also add that, while *using* genericised classes and methods is pretty straightforward, actually *writing* generics in Java is painful. Almost physically so. I'm sure if I had to do it every day for two weeks I'd get over the learning curve, but...