[Contents]
[Prev] [Next] [Limbo Basics] [Limbo Programming] [Language Definition]

Referring to Modules

As discussed above, modules present constants, data variables, functions, and types in their interface. Their names can 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 the M module 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 or object defined either as a top-level member of the module, or as a member of one of its adts, 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 or object 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, objects 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, objects, and adt's 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 and data objects declared in Mod are imported as well, and refer dynamically to the current instance of the module being implemented.



[Contents]
[Prev] [Next] [Limbo Basics] [Limbo Programming] [Language Definition]

Copyright © 1998, Lucent Technologies, Inc. All rights reserved.