Previous Table of Contents Next


11.7.1. Import Statements

There are two forms of import statements. All imports of both forms are interpreted simultaneously: Their order doesn’t matter.

The first form is

   IMPORT I AS J

which imports the interface whose global name is I and gives it the local name J. The entities and revelations declared in I become accessible in the importing module or interface, but the entities and revelations imported into I do not. To refer to the entity declared with name N in the interface I, the importer must use the qualified identifier J.N.

The statement IMPORT I is short for IMPORT I AS I.

The second form is

   FROM I IMPORT N

which introduces N as the local name for the entity declared as N in the interface I. A local binding for I takes precedence over a global binding. For example,

   IMPORT I AS J, J AS I; FROM I IMPORT N

simultaneously introduces local names J, I, and N for the entities whose global names are I, J, and J.N, respectively.

It is illegal to use the same local name twice:

   IMPORT J AS I, K AS I;

would be a static error if J and K were the same.

11.7.2. Interfaces

An interface has the form

   INTERFACE id;  Imports;  Decls END id.

where id is an identifier that names the interface, Imports is a sequence of import statements, and Decls is a sequence of declarations that contains no procedure bodies or non-constant variable initializations. The names declared in Decls and the visible imported names must be distinct. It is a static error for two or more interfaces to form an import cycle.

11.7.3. Modules

A module has the form:

   MODULE id EXPORTS Interfaces;  Imports; Block id.

where id is an identifier that names the module, Interfaces is a list of distinct names of interfaces exported by the module, Imports is a list of import statements, and Block is a block, the body of the module. The name id must be repeated after the END that terminates the body. EXPORTS Interfaces can be omitted, in which case Interfaces defaults to id.

If module M exports interface I, then all declared names in I are visible without qualification in M. Any procedure declared in I can be redeclared in M, with a body. The signature in M must be covered by the signature in I. To determine the interpretation of keyword bindings in calls to the procedure, the signature in M is used within M; the signature in I is used everywhere else.

Except for the redeclaration of exported procedures, the names declared at the top level of Block, the visible imported names, and the names declared in the exported interfaces must be distinct.

For example, the following is illegal because two names in exported interfaces coincide:

   INTERFACE I;  INTERFACE J;    MODULE M EXPORTS I, J;
     PROCEDURE X();  PROCEDURE X();  PROCEDURE X() = ...;

The following is also illegal because the visible imported name X coincides with the top-level name X:

   INTERFACE I;  MODULE M EXPORTS I;  FROM I IMPORT X;
     PROCEDURE X();  PROCEDURE X() = ...;

But the following is legal, although peculiar:

   INTERFACE I;  MODULE M EXPORTS I;  IMPORT I;
     PROCEDURE X(...);  PROCEDURE X(...) = ...;

because the only visible imported name is I, and the coincidence between X as a top-level name and X as a name in an exported interface is allowed, assuming the interface signature covers the module signature. Within M, the interface declaration determines the signature of I.X and the module declaration determines the signature of X.

11.7.4. A Sample Module and Interface

Here is the canonical example of a public stack with hidden representation:

   INTERFACE Stack;
     TYPE T <: REFANY;
     PROCEDURE Create(): T;
     PROCEDURE Push(VAR s: T; x: REAL);
     PROCEDURE Pop(VAR s: T): REAL;
   END Stack.

   MODULE Stack;
     REVEAL T = BRANDED OBJECT item: REAL; link: T END;
     PROCEDURE Create(): T = BEGIN RETURN NIL END Create;
     PROCEDURE Push(VAR s: T; x: REAL) =
       BEGIN
         s := NEW(T, item := x, link := s)
       END Push;
     PROCEDURE Pop(VAR s: T): REAL =
       VAR res: REAL;
       BEGIN
         res := s.item; s := s.link; RETURN res
       END Pop;
   BEGIN
   END Stack.

If the representation of stacks is required in more than one module, it should be moved to a private interface so that it can be imported wherever it is required:

   INTERFACE Stack (* ... as before ... *) END Stack.
   INTERFACE StackRep; IMPORT Stack;
     REVEAL Stack.T = BRANDED OBJECT item: REAL; link: Stack.T END
   END StackRep.

   MODULE Stack; IMPORT StackRep;
     (* Push, Pop, and Create as before *)
   BEGIN
   END Stack.

11.7.5. 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, F1, ..., Fn 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 nongeneric 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 A1, ...,An 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 G.

where G is an identifier that names the generic module, F1, ..., Fn 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 nongeneric module.

An instance of G has the form

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


Previous Table of Contents Next