term -> termdenotes module qualification. The first term identifies a module: either it is a module type name, or it is an expression of module type. The second term is a constant name, type, data object, or function specified within that module's declaration. Either the module type name or an object of the module's type suffices to qualify constants and types; functions and objects directly exported by the module or contained within its
adt
must be qualified by an object of the module's type, initialized with load
.
An example using an abridged version of an example given above:
Linear : module { setflags : fn (flag : int); TRUNCATE : con 1; Vector : adt { v : array of real; add : fn (v1 : self Vector, v2: Vector) : Vector; make : fn(v : array of real) : Vector; }; };one might say:
lin := load Linear "/dis/linear.dis"; a : array of real; v1 : lin -> Vector; v2 : Linear -> Vector; lin->setflags (Linear->TRUNCATE); v1 = lin->(Linear->Vector).make(a); v1 = lin->v1.make(a); v1 = lin->v1.add(v1); v1.v = nil;Here, the declarations for
v1
and v2
are equivalent; either a module type name (here, Linear
) or a handle (here, lin
) suffices to identify the module. In the call to setflags
, a handle is required for the call itself; the type name is sufficient for the constant.
When calling a function associated with an adt
of another module, it is necessary to identify both the module and the adt
as well as the function. The two calls to the make
function illustrate two ways of doing this. In the first,
v1 = lin->(Linear->Vector).make(a);the module handle
lin
is specified first, then the type name of the Vector adt
within it, and then the function. In the second call:
v1 = lin->v1.make(a);instead of using a type name to specify the
adt
, an instance of an object of the appropriate type is used instead. In the first example, the parentheses are required because the qualification operators associate to the left.
v1 = lin->Vector.make(a); #Wrong v1 = lin->Linear->Vector.make(a); #WrongThe first is wrong because the same
lin
can't serve as a qualifier for both the type and the call; the second is wrong because lin->Linear
is meaningless.
Using import
makes the code less verbose:
lin := load Linear "/dis/linear.dis"; Vector, TRUNCATE, setflags : import lin; a : array of real; v1 : Vector; v2 : Vector; setflags (TRUNCATE); v1 = Vector.make(a); v1 = v1.make(a); v1 = v1.add(v1); v1.v = nil;
Note: You canimport
from either a module type or a module instance, but in the former case, you cannot use it to import functions and data objects.