Generics: Commentary

Steven Zeil

Last modified: Oct 5, 2016
Contents:

1 Why Use Generics?

Generics in Java are similar to templates in C++.

Templates were a fairly late addition to C++. The need for them was recognized fairly early, but coming up with a mechanism that made sense from a language design standpoint and that could be effectively implemented in compilers took quite a few years. During that time, multiple proposals were floated, prototype implementations were made available, and programmers reported on the usefulness of those proposed approaches. Even when the syntax and semantics of templates was finalized in the draft international standard for C+, templates remained a source of bugs in compilers and frustration for programmers for some time.

Generics came into Java at an even later stage in its development, relatively speaking. The general attitude during the early versions of Java seemed to be “Templates? We don’t need no stinkin’ templates!”. Many seemed to believe that Java’s more pervasive use of inheritance made templates unnecessary. The complications experienced by C++ compiler writers further contributed to an idea that templates were just too complicated and that Java would do better to stay away from them.

Over time it became clear, as suggested in the next section, that basing the data structures in the API upon a purely inheritance-based scheme contributed to a lot of run-time errors in Java code that could have been detected at compile-time with more rigorous checking. Version 5 of Java eventually introduced generics.

The difference in naming is interesting (at least, to me). C++ and Java were not the first prominent programming languages to have a generic/template mechanism. Ada, the programming language sponsored by the US Dept. of Defense in the late 1970’s and early 1980’s, had “generics” that worked much like C++ templates but offered some of the more rigorous compiler checks favored by Java. I’ve always felt that it was a touch of hacker snobbery to distance C++’s mechanism from Ada’s by changing the name. In fairness, “template” is more descriptive of how many C++ programmers think about them: as a kind of source code pattern where the compiler “fills in the blanks” to generate source code for a new function or class.

And it seems equally in character for the Java community to select a distinctive term from that used in C++ to distance them from the C++ community. (Think back to the earlier discussion of “reference” in Java versus “reference” and “pointer” in C++ and the common claim by Java aficionados that Java is simpler than C++ because it has no pointers.) In fairness, Java’s mechanism is not thought of as a text substitution to generate new code (as in C++), but as a mechanism for describing, to the compiler, limits on we intend to employ a class or function that is otherwise much more general (generic) than we really need.

2 Generic Types

The C++ equivalent of the Box generic would be:

template <typename T>
class Box {
   // T stands for "Type"
   T t;
   public:
   void add(T t) {
      this.t = t;
   }

   T get() {
      return t;
   }
};

Really, not much difference at all.

The invocation of the generic to create the variable integerBox:

Box<Integer> integerBox;

is identical to the way that a C++ programmer would instantiate the template to create that variable.

3 Generic Methods

What is described here is equivalent to the idea of a function template in C++, once you take into account the fact that in Java all functions must be members of a class. In C++, function templates can be either members of a class of standalone functions.

4 Bounded Type Parameters

5 Generics, Inheritance, and Subtypes

This page, and the next two pages, will make much more sense later when we have discussed inheritance in more detail.

6 Type Inference

It may be worth noting that, in C++, this is all handled at compile time. In the main, this happens because each instantiation of a template produces a copy of that template’s code, with appropriate substitutions for the template parameters. For example, a std::vector<int> and a std::vector<string> appearing in the same program would yield two distinct blocks of code, one for a vector-of-int class and one for a vector-of-string class.

By contrast, Java generics use a single copy of the code that interacts, as necessary, with the types supplied for the generic parameters. Much of this is done at run-time, though there is a certain amount of compile-time effort so that the compiler understants the types of expressions, e.g., that aVector.get(i) has type int if aVector is a Vector<int>.

7 Wildcards

Again, you may want to return to this section after we have covered inheritance.

8 Type Erasure

This page discusses how Java actually implements generics. It’s the alternative to the view in C++ of templates as a kind of “fill-in-the-blank” text operations to generate new source code.

It’s not really a credit to the Java language that this mechanism needs to be explained to programmers at all. Luckily, it’s usually only an issue when dealing with Java code left over from Java versions 1-4. Unfortunately, there’s a lot of such code around, including in some widely used open-source libraries.

9 Restrictions on Generics