Modula-3: Generics

# Generics

In a generic interface or module, some of the imported interface names are treated as formal parameters, to be bound to actual interfaces when the generic is instantiated.

A generic interface has the form

        GENERIC INTERFACE G(F_1, ..., F_n);
          Body
        END G.

where `G` is an identifier that names the generic interface, `F_1`, `...`, `F_n` is a list of identifiers, called the formal imports of `G`, and `Body` is a sequence of imports followed by a sequence of declarations, exactly as in a non-generic interface.

An instance of `G` has the form

        INTERFACE I = G(A_1, ..., A_n) END I.

where `I` is the name of the instance and `A_1`, `...`, `A_n` is a list of actual interfaces to which the formal imports of `G` are bound. The instance `I` is equivalent to an ordinary interface defined as follows:

        INTERFACE I;
          IMPORT A_1 AS F_1, ..., A_n AS F_n;
          Body
        END I.

A generic module has the form

        GENERIC MODULE G(F_1, ..., F_n);
          Body
        END G.

where `G` is an identifier that names the generic module, `F_1`, `...`, `F_n` is a list of identifiers, called the formal imports of `G`, and `Body` is a sequence of imports followed by a block, exactly as in a non-generic module.

An instance of `G` has the form

        MODULE I EXPORTS E = G(A_1, ..., A_n) END I.

where `I` is the name of the instance, `E` is a list of interfaces exported by `I`, and `A_1`, `...`, `A_n` is a list of actual interfaces to which the formal imports of `G` are bound. "`EXPORTS E`" can be omitted, in which case it defaults to "`EXPORTS I`". The instance `I` is equivalent to an ordinary module defined as follows:

        MODULE I EXPORTS E;
          IMPORT A_1 AS F_1, ..., A_n AS F_n;
          Body
        END I.

Notice that the generic module itself has no exports; they are supplied only when it is instantiated.

For example, here is a generic stack package:

        GENERIC INTERFACE Stack(Elem);
          (* where Elem.T is not an open array type. *)
          TYPE T <: REFANY;
          PROCEDURE Create(): T;
          PROCEDURE Push(VAR s: T; x: Elem.T);
          PROCEDURE Pop(VAR s: T): Elem.T;
        END Stack.

        GENERIC MODULE Stack(Elem);

          REVEAL
            T = BRANDED OBJECT  n: INTEGER;  a: REF ARRAY OF Elem.T  END;

          PROCEDURE Create(): T =
            BEGIN  RETURN NEW(T, n := 0, a := NIL)  END Create;

          PROCEDURE Push(VAR s: T; x: Elem.T) =
            BEGIN
              IF s.a = NIL THEN
                s.a := NEW(REF ARRAY OF Elem.T, 5)
              ELSIF s.n > LAST(s.a^) THEN
                WITH temp = NEW(REF ARRAY OF Elem.T, 2 * NUMBER(s.a^)) DO
                  FOR i := 0 TO LAST(s.a^) DO temp[i] := s.a[i] END;
                  s.a := temp
                END
              END;
              s.a[s.n] := x;
              INC(s.n)
            END Push;

          PROCEDURE Pop(VAR s: T): Elem.T =
            BEGIN  DEC(s.n);  RETURN s.a[s.n]  END Pop;

        BEGIN
        END Stack.

To instantiate these generics to produce stacks of integers:

        INTERFACE Integer; TYPE T = INTEGER; END Integer.
        INTERFACE IntStack = Stack(Integer) END IntStack.
        MODULE IntStack = Stack(Integer) END IntStack.

Implementations are not expected to share code between different instances of a generic module, since this will not be possible in general.

Implementations are not required to typecheck uninstantiated generics, but they must typecheck their instances. For example, if one made the following mistake:

        INTERFACE String; TYPE T = ARRAY OF CHAR; END String.
        INTERFACE StringStack = Stack(String) END StringStack.
        MODULE StringStack = Stack(String) END StringStack.

everything would go well until the last line, when the compiler would attempt to compile a version of `Stack` in which the element type was an open array. It would then complain that the `NEW` call in `Push` does not have enough parameters.

    Last modified on Wed Apr  3 09:39:52 PST 1996 by heydon
         modified on Mon Apr 18 14:03:26 PDT 1994 by kalsow