Copyright © 1996, 1997 Lucent Technologies Inc. All rights reserved.
10 Referring to modules;
import
As discussed above, modules present
constants, functions, and types
in their interface.
Their names may be the same as names
in other modules or of local objects or types within
a module that uses another.
Name clashes are avoided because references
to the entities presented by a module are
qualified by the module type name or an object
of that module type.
For example,
after the module and variable declarations
M: module {
One: con 1;
Thing: adt {
t: int;
f: fn();
};
g: fn();
};
m: M;
the name
One
refers to the constant defined in
module
M
only in the contexts
M->One
or
m->One;
the name
Thing
as the particular data type
associated with the
M
module can be referred to only in contexts
like
th1: M->Thing;
th2: m->Thing;
Finally, to call a function defined either as a top-level
member of the module, or as a member of one of its
adt,
it is necessary to declare, and also dynamically initialize using
load,
a handle for the module.
Then calls of the form
m->g();
m->th1.f();
become appropriate.
It is possible to use just the type name of a module to qualify
its constants and types because constants and types can be understood
without having the code and data present.
Calling a function declared by a module or one of its
adt
requires loading the module.
The
import
declaration
identifier-list : import identifier ;
lifts the identifiers in the
identifier-list
into the scope in which
import
appears, so that they are usable without a qualifier.
The identifier after the
import
keyword is either
a module identifier, or an identifier declared as having
that type.
The initial list of identifiers specifies those
constants,
types,
and functions of the module whose names are promoted.
In the case of constants and types,
import
merely makes their names accessible without using a qualifier.
In the example above, if the
module
declaration above had been followed by
One, Thing: import M;
then one could refer to just
One
instead of
M->One;
similarly an object could be declared like
th: Thing;
For functions, and also
adt
with functions as members,
import
must specify a module
variable (as opposed to a module identifier).
Each imported name is associated with the specified module
variable, and the current value of this module variable
controls which instance of the module will
be called.
For example, after
g, Thing: import m;
then
g();
is equivalent to
m->g();
and
th: Thing;
th.f();
is equivalent to
th: M.Thing;
m->th.f();
When the module declaration for the module being
implemented is encountered, an implicit
import
of all the names of the module is executed.
That is, given
implement Mod;
. . .
Mod: module {
. . .
};
the constants and types of
Mod
are accessed as if they had been imported;
the functions declared in
Mod
are imported as well, and refer dynamically to the
current instance of the module being implemented.
05/Jun/97