Below you will find links to a detailed specification of the proposed changes. For the benefit of those with a deeper technical interest in genericity, the background section discusses design alternatives that were considered by the expert group.
The current proposal evolved from the GJ
project. The current draft is upward compatible with the GJ specification
(with one very minor caveat). The differences compared
to the original GJ proposal are detailed below.
Most proposals for adding generics to the Java programming language
have a great deal in common. The main points where they differ are in the
treatment of primitive types and in the degree of support for generic types
at run time.
Consequently, those two areas have engendered the most controversy.
These are discussed in some detail below.
This proposal is carefully designed so as not to preclude further
evolution. In particular, in the two main areas of controversy,
the additional functionality desired by critics of this proposal could
be added in the future if warranted.
The draft disallows generic exception classes (that is, subclasses of Throwable that are generic). This is the only incompatibility with GJ. The usefulness of such exception classes would be very limited in any case, because the exception catching mechanism in the VM does not support genericity.
The draft allows for the bounds of type variables to contain both a single class and multiple interfaces. This feature had been omitted from GJ for simplicity's sake. User feedback has indicated that in some cases this functionality is valuable, and so it has been added.
The draft provides limited support for reflection on generic constructs. The specification allows reflective examination of the generic elements of program structure, such as the declarations of type variables and the use of parametric types in arguments, return types and declared types of fields. It does not support any uses that require a run-time association between generic type information and individual objects.
The philosophical argument is simply that the existing language clearly distinguishes between primitive types and reference types. There is no context where one can write code that works for both primitive types and reference types. Allowing generics that work for both reference types and primitive types requires such a context to be established. This a significant change that runs counter to the existing structure of the Java programming language.
A philosophical counter argument makes a comparison with arrays. Arrays are a "generic" type, and arrays of primitive type are supported. However, arrays are built-in; no user-defined code is involved and so the problem noted above does not arise. In the case of arrays, the amount of code that needs to be replicated for the different primitive types is small and the actual code is known in advance to the VM implementation. The engineering trade-offs are therefore very different.
Even if one chooses the ignore the conceptual issues raised above, significant
engineering problems arise. Support for primitive types as generic type
arguments interacts with the overall translation scheme from the new language
to the existing virtual machine language, as discussed below.
A variation that circumvents some of the conceptual difficulties is to uniformly declare that primitive types are in fact subtypes of their corresponding reference types. For example, int would be a subtype of Integer and so on. The "boxing conversion" would be done automatically. A more limited form of such a conversion is under consideration in the context of JSR-65, Concise Object Array Literals. Introducing this conversion uniformly throughout the Java programming language is a fairly significant change to the language, and is arguably beyond the charter of the expert group. A separate JSR that dealt with this "autoboxing" issue is highly promising avenue for further work.
Heterogeneous translations make it possible to create distinct code when a generic is instantiated on a distinct primitive type. The resulting code is easy to optimize for speed. Unfortunately, using a heterogeneous translation in general leads to unacceptable increase in footprint. This has proven to be problematic in the C++ world, where templates are usually implemented via a macro expansion somewhat like heterogeneous translation. Load time expansion, as proposed by Agesen et al., addresses some of the distribution and disk space concerns, but not the memory footprint problems. It also requires VM support. The problem is much more acute for the Java programming language, which must be implementable on small footprint devices such as PDAs, mobile phones and so forth.
Heterogeneous translation also raises semantic questions. A heterogeneous translation creates multiple classes for the same generic definition. This is incompatible with existing semantics. For example, it would not be possible to make the existing collection classes generic if distinct generic instantiations of these classes had distinct identity, since existing programs rely on that identity. While some would argue that only new code should be made generic, this argument is unrealistic. Shipping multiple collection libraries is unacceptable for several reasons. One is the need to avoid bloating of distributions with multiple versions of essentially equivalent code.
Another, much more crucial consideration, is the need for different software libraries to evolve independently while still interoperating. Assume two modules communicate using collections. If the generic collections were incompatible with the non-generic ones, then both modules would have to either keep using the old version, or switch to the new one simultaneously. This is unrealistic if the two modules are developed by independent entities.
Of course, the above considerations are not restricted to collections. Many vendors would like to be able to make their existing APIs generic without any compatibility concerns. It would be inconceivable to produce new versions of all these APIs and deal with the resulting confusion and distribution problems.
Of course, the class identity issue also makes the heterogeneous solution
incompatible with the homogeneous one. This is one reason why we
could not view the translations as an implementation issue, and allow for
distinct implementations to choose different translations (so that PDAs
used a homogeneous approach, while large scientific projects used a heterogeneous
approach).
Supporting generic types at run time seems undesirable for the following
reasons:
Run time support for genericity has not been implemented in any
major programming language, and research efforts are also extremely few.
Consequently, the body of experience with such constructs is very limited.
It is therefore inappropriate to deploy such constructs in a widely
used, mission critical language. The risks are too great.
Beyond the general principle of relying on well understood technology, the following discussion should make it clear just how big a technological risk is involved.
Supporting generic types at run time implies that such information is passed around at run time. This effects the linkage of constructors for generic type declarations and of generic methods. If existing binaries are allowed to link to generic ones, as they must, special logic must exist as part of the VM resolution process to allow the non-generic call to link with the generic declaration. This implies VM support. It also implies that the class file format reflect the generic information.
In addition, the cost of maintaining and transmitting generic type information at run time translates to potentially significant performance degradations when generic methods or constructors are used. Highly tuned implementations may be able to optimize the cost of generic constructors. However, there are no known techniques that effectively eliminate the overhead for generic methods. In addition, the negative effects on small VMs which cannot afford the space penalties of such optimizations should not be ignored. The space required for representing generic type information at run time is also a problem for small VMs.
A legitimate trade-off might be to forego generic methods and support run-time type information. This is the choice made in PolyJ, for example. However, this would not address any of the other issues raised here. Furthermore, generic methods are extremely valuable in APIs such as the collections library.
If generic types are represented in the class file format, one might reasonably expect the byte code verifier must be able to deal with generic types. Thus the polymorphic type system becomes part of the trusted code base for Java platform security. This is very undesirable because of the complexity involved and because we wish decrease rather than increase the size of the trusted code base.
All this increased complexity must be supported by all Java virtual machines. This would makes the Java platform much less suited for small embedded applications, and poses a huge burden on VM vendors.
Overall, it is clear that a compatible extension would require VM modifications. Furthermore, the performance implications are uncertain, and are especially worrisome for small VMs. It is possible that future research will address these issues and conclusively show how to produce fast, compact and compatible implementations that support generic types at run-time. However, it would be irresponsible to mandate such an extension at this time.
interface CCT = Collection<Collection<Thread>>
This was rejected because:
A significant user community has been programming with the language and APIs described in this proposal for approximately three years, and with a similar system (Pizza) for two years prior to that.
We anticipate releasing our experimental implementation in the very
near future (see below).
A experimental implementation should be publicly available in the
very near future. Please check
the
generics update page for details.
The GJ web
site contains a GJ
tutorial that is also a good introduction to the kind of features described
by this extension. You can expect a detailed tutorial in the tradition
of the Java Tutorials in the future.
The GJ site also contains the OOPSLA
98 GJ paper, which gives a rigorous discussion of the GJ design. This
paper is still highly relevant to the proposed extension.
Copyright © 1995-2001 Sun
Microsystems, Inc.
All Rights Reserved. Terms
of Use. Privacy Policy.