Search code examples
javagenericsbackwards-compatibility

How did type erasure in Java protect backward compatibility?


I've been learning Java generics recently, and I got to know that the reason Java adopted the type erasure approach to implementing generics is to ensure backward compatibility.

But I don't quite understand how this approach ensured backward compatibility. Since programs are not required to be generic, why having true generics will violate backward compatibility?


Solution

  • This is discussed in the Java Language Specification, on page 57:

    The decision not to make all generic types reifiable is one of the most crucial, and controversial design decisions involving the language’s type system.

    Ultimately, the most important motivation for this decision is compatibility with existing code.

    Naively, the addition of new constructs such as genericity has no implications for preexisting code. The programming language per se, is compatible with earlier versions as long as every program written in the previous versions retains its meaning in the new version. However, this notion, which may be termed language compatibility, is of purely theoretical interest. Real programs (even trivial ones, such as "Hello World") are composed of several compilation units, some of which are provided by the Java platform (such as elements of java.lang or java.util).

    In practice then, the minimum requirement is platform compatibillity [sic] - that any program written for the prior version of the platform continues to function unchanged in the new platform.

    One way to provide platform compatibillity is to leave existing platform functionality unchanged, only adding new functionality. For example, rather than modify the existing Collections hierarchy in java.util, one might introduce a new library utilizing genericity.

    The disadvantages of such a scheme is that it is extremely difficult for pre-existing clients of the Collection library to migrate to the new library. Collections are used to exchange data between independently developed modules; if a vendor decides to switch to the new, generic, library, that vendor must also distribute two versions of their code, to be compatible with their clients. Libraries that are dependent on other vendors code cannot be modified to use genericity until the supplier’s library is updated. If two modules are mutually dependent, the changes must be made simultaneously.

    Clearly, platform compatibility, as outlined above, does not provide a realistic path for adoption of a pervasive new feature such as genericity. Therefore, the design of the generic type system seeks to support migration compatibility. Migration compatibiliy allows the evolution of existing code to take advantage of generics without imposing dependencies between independently developed software modules.

    The price of migration compatibility is that a full and sound reification of the generic type system is not possible, at least while the migration is taking place.

    To put it another way, not erasing type parameters would require that a "raw" type and a parameterised type be treated as different types. This would render legacy code written with raw types non-interoperable with APIs written for generic types, and vice-versa.

    There is a more detailed discussion in the paper Making the future safe for the past: Adding Genericity to the JavaTM Programming Language by Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler. This describes the "GJ" project, which was the basis for the inclusion of generics in Java 5.