Entity definitions are packaged within modules. The syntax and semantics of RSL modules are similar to that of the Modula-2 programming language [Wirth 85]. The semantics of modules, though not the syntax, are similar to packages in the Java programming language [Gosling 00]. The basic format of an RSL module is the following:
module name ;Module imports and exports optionally define inter-module name visibility. Attribute-definitions specify user-defined attributes, as described in Section 6 below. If any attribute definitions are present, they must appear before entity definitions. Entity-definitions are objects and operations, as described in Section 3. Formal-definitions are discussed in Sections 7 and 8.
[imports]
[exports]
[attribute-definitions ... ;]
[entity definition; |
formal definition; ] ...
end name
In terms of packaging, a module defines a name scope within which all defined entities are visible. Any definition within a given module may reference any other entity defined within the same module. Unlike many programming languages, an entity definition does not need to lexically precede its reference(s) within a module.
Normally, entities defined in two different modules are mutually invisible. For example if object A is defined in module M1 and operation B is defined in module M2, the definition of B cannot reference A as an input or output. The use of import and export declarations extends the visibility of names between modules. The general format of an import declaration is the following:
from module-name import entity- name,...and the format of export is:
export entity-name,...The entity-name list may be the single keyword all, which means that all entities defined are imported or exported. In the case of the import declaration, the entity-list may be of the form
all except entity-name,...which means that all entities except those listed are imported.
Consider the following example:
The import declaration in B makes object O1 visible within B. Hence, the reference to O1 in Op1 is fine. Since object O2 is not explicitly imported into B, the reference to O2 in Op2 is illegal.module A; export O1; object O1 is ... ; object O2 is ... ; end A; module B; from A import O1; operation Op1 is inputs: O1, ... ; (* Legal reference to O1 *) end Op1 operation Op2 is inputs: O2, ... ; (* Illegal reference to O2 *) end A;
It should be noted that imports must be matched by corresponding exports. That is, a name cannot be import into one module without having been exported from another. Conversely, if a module exports one or more entities, each of these entities must be referenced by at least one import.
The use of import/export can lead to name conflicts if a module both imports and defines an entity of the same name. For example:
Here module B both imports and defines O1. To overcome such name conflicts, names can be imported in qualified form, and referenced by prefixing with the name of the defining module. Qualified imports are achieved by importing an entire module, without the use of the from clause. The following is a version of the immediately preceding example with the name conflict removed:module A; export O1; object O1 is ... ; end A; module B from A import O1; object O1 is ... ; (* Name conflict *) operation Op is inputs: O1; (* Ambiguous reference *)
Here, reference to the imported version of O1 is denoted by the qualified reference "A.O1" within B. The unqualified reference to O1 refers to the O1 defined within B. Hence, there is no name conflict in this case, since both versions of O1 can be referenced unambiguously.module A; export O1; object O1 is ... ; end A; module B import A; object O1 is ... ; (* No conflict *) operation Op is inputs: O1; (* Legal reference to B's O1 *) outputs: A.O1; (* Legal reference to A's O1 *) end B;
When a module contains many definitions that all need to be exported, the all form of import/export is convenient. For example,
The difference between importing an entire module by name versus importing all of its entities is a matter of qualification. That is, the import declarationmodule A; export all; object O1 is ... ; ... object O100 is ... ; end A; module B from A import all; ... end B;
makes all exports of A available only in qualified form. The importimport A
makes all exports of A available in unqualified form.from A import all
Whenever a module name appears in an import declaration, either in the from clause or in the entity name list, all of its exports are accessible in qualified form. For example,
In this case, objects O1, O2, and O3 are accessible in unqualified form within module B. Objects O4 through O100 are accessible in qualified form within B. For example, A.O56 is a valid reference to object O56 from module A. Unqualified imports are also available in qualified form, for example both O2 and A.O2 are valid references within module B. However, there is typically no reason to reference unqualified imports in qualified form, unless there is a desire to emphasize that a particular entity comes from a particular module.module A export all; object O1 is ... ; ... object O100 is ... ; end A; module B from A import O1, O2, O3; ... end B;
As explained above, unqualified imports will conflict with definitions of the same name in the importing module. There are two ways to deal with such potential conflicts. If an exporting module only needs to make visible some of its definitions, then selectively listing those in the export declaration can avoid conflicts with other modules that import all if its definitions. Alternatively, if a module exports all of its definitions, an importing module can import all but a selected list of the exports to avoid conflicts. Consider this example:
In this case, module B needs all of module A's exports, except for object O56. To avoid conflict with this object, the import declaration includes the all except clause, which causes O56 to be excluded from the list of unqualified imports. In this way, the definition of O56 in module B does not conflict with that in module A. The version of O56 from A is still available in module B in qualified form, i.e., as A.O56.module A; export all; object O1 is ... ; ... object O56 is ... ; ... object O100 is ... ; end A; module B from A import all except O56; object O56 is ... ; ... end B;