JSR-14 Public Draft

Summary

This page and the referenced documents describe the proposed extension of the Java Programming Language with generic type declarations and methods (JSR-14). The proposed extension has absolutely no effect on  the Java Virtual Machine specification. Rather, the extension affects the Java programming language and certain key libraries (collections in particular).

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.

Language Changes

All proposed language changes, including mechanisms for compiling them, are described in the  specification of  proposed language modifiations. The changes are absolutely upward compatible with the existing Java programming language described in the Java Language Specification, Second Edition. All existing binaries and source files remain valid.

Library Changes

Collections

Generic type information will be added to the Collections library. This does not have any effect whatsoever on users of the collection library. The semantics of the collection classes remain unchanged. As noted above, all existing binaries and source files remain valid. Here are the affected APIs.

Reflection

Limited support for structural reflection on generics is included in this draft. The relevant extensions are
given here.

Background and Rationale


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.
 

Differences compared to GJ

The draft allows the use of type variables in throws clauses. This supports an important style of programming where inner classes are used almost like closures. The draft contains a realistic example that illustrates this style.

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.

Differences compared to the Community/Participant draft

We have added support for reflection to the existing proposal. These require minor adjustments to the Java virtual machine.  Originally, we were very keen to avoid any VM changes because of the burden this might place on the industry as a whole. However, circumstances have changed over time. It has become apparent that the extensions proposed here will not be productized until the 1.5 release of the Java platform, rather than the 1.4 release as we had originally anticipated. Realistically, we expect some VM adjustments to be done in that time frame in any case, so the penalty for adding reflection support is no longer as onerous. Given this change of circumstances and the real need and demand for reflection support, we took the opportunity to add limited reflective support for generics during the public review period.

Treatment of Primitive Types

The original JSR indicated that supporting primitive type parameters to generics was not a goal of the project. This was based both on philosophical considerations and on technical problems.

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.
 

Choice of Translation Scheme

A homogeneous translation similar to the existing proposal can be extended to support primitive types. However, such an approach does not address one of the primary arguments made for abstracting over primitive types, which is to increase the performance of numerical codes. Rather, it creates a situation where users may be radically misled as to the performance characteristics of a generic class. Given the conceptual problems associated with supporting primitive types in generics, a solution that does not provide the "expected" performance benefits seems unattractive.

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).
 

Treatment of Generic Types at Run-time


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.

Design Trade-offs Considered

A variety of design trade-offs were considered at different times. One is worth mentioning here, because it was a close call, and because further user comment on it is particularly valuable.

Type Aliases

We considered the possibility of type aliases, such as

interface CCT = Collection<Collection<Thread>>

This was rejected because:

Implementation Status

The proposed language and library changes (except reflection) have been completely implemented in a production quality compiler. In fact, the current shipping version of javac in the J2SE 1.3 SDK is automatically derived from a compiler that accepts the extended language.

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).
 

Additional Resources


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.