[Ada Information Clearinghouse]
Ada '83 Rationale, Sec 12.1: Introduction (to Ch 12: Generic Units)

"Rationale for the Design of the
Ada® Programming Language"

[Ada '83 Rationale, HTML Version]

Copyright ©1986 owned by the United States Government. All rights reserved.
Direct inquiries to the Ada Information Clearinghouse at adainfo@sw-eng.falls-church.va.us.

CHAPTER 12: Generic Units

12.1 Introduction

Generic units are a general form of parameterized program units. As with other parameterization mechanisms, the primary purpose is factorization, resulting in a reduction in the size of the program text while also improving maintainability, readability, and efficiency.

Parameterization by generic units is a natural extension of subprogram parameterization. When otherwise identical actions differ by a particular value or variable, these actions may be encapsulated in a subprogram where the value or variable appears as a parameter. Having thereby factored out the common part, the text becomes smaller and easier to read; and clerical errors, resulting from accidental lack of identity among the copies, are eliminated. Moreover, compilers can take advantage of this commonality to produce more compact code.

Traditional parameterization mechanisms are usually in terms of values and variables. But the same factorization arguments apply when two otherwise identical program units differ by some other property, such as a type.

A classical example is provided by stacks. In Ada, stacks would typically be formulated as a private type, encapsulated with its associated operations within a package. Although one may want to have stacks of integers and stacks of real numbers, it is clear that neither the stack algorithms, nor the proof of their correctness, depends upon the type of the items to be stacked. However, the typing rules will not allow the writing of a single procedure to deal with items that are either integer or real values: if this were allowed, there would be no way to guarantee that a given stack does not contain intermixed integer and real values. Hence another parameterization mechanism is needed to express the intent that, although all items of a stack have the same type, we may want to specify this type independently for individual stacks: this parameterization mechanism is what is provided by the generic formal part of a generic unit.

Generic units are parameterized program units (for example, generic packages) for which parameters can be types and subprograms as well as values and variables. Replication of text can thereby be avoided, yielding better readability and maintainability. In addition, compilers may use their knowledge of type representations to achieve certain optimizations; for example, reusing the same code for stacks of integers and reals if the same number of bits is used for the mapping of values of these types. Seen in this light, the generic facility provides a natural complement to strong typing, minimizing the unnecessary duplication of both source text and object code.

One of the commonest applications of any generic facility is factoring out dependences on particular types. Several earlier languages have accordingly introduced language features to accommodate this sort of parameterization. By far the most powerful is that provided by the language EL1; however, this generality is achieved at the cost of interpreting types in a fully dynamic fashion, which is incompatible with the efficiency and security criteria imposed in the present context.

Languages such as Simula, Clu, and Mary offer a reasonably elegant approach to this problem, but all require that all objects be handled by reference. This introduces additional overhead - namely, indirect access - even in cases where this generality is neither needed nor wanted. To some degree, type discriminants and variants (such as in Euclid and Ada) or type unions (such as in Algol 68) provide a possible approach when the alternative types are known in advance; similarly the language CS-4 provides a limited facility that may only be used in conjunction with predefined types. Neither approach offers the flexibility that is required when the definition of new data types is viewed as the rule rather than the exception.

A review of the shortcomings of existing mechanisms that allow types to be used as parameters showed that it was inappropriate to introduce overly elaborate language features solely for this purpose, principally because the same effect (and many others as well) can be essentially achieved by far simpler means using traditional macro- expansion techniques - although in a context-sensitive manner. The problem then reduced to integrating this well-established approach into the framework of a high-order language at reasonable cost.

In Ada, the more sophisticated sorts of parameterization are accommodated by generic program units, which are a restricted form of context-sensitive macro facility. The main objectives in providing this particular mechanism have been:

Address any questions or comments to adainfo@sw-eng.falls-church.va.us.