| Symbols | categories I/O, Modules and System Interface Modules |
Global Variables and Constants |
Organizing software into modules is a key aspect of software engineering : modules separate different features as well as different levels of abstraction for a given task. To avoid messy designs and to encourage modular programming, programs can be structured into modules, which all have their own identifiers and may hide them to other modules. A module is thus a namespace that can be visible or hidden for other modules. CLAIRE supports multiple namespaces, organized into a hierarchy similar to the unix file system. The root of the hierarchy is the module CLAIRE, which is implicit. A module is defined as a usual CLAIRE object with two important slots: part_of which contains the name of the father module, and a slot uses which gives the list of all modules that can be used inside the new module. For instance :
| interface :: module(part_of = library, uses = list(claire)) |
Definition : A module is a CLAIRE object that represents a namespace. A namespace is a set of identifiers : each identifier (a symbol representing the name of an object) belongs to one unique namespace, but is visible in many namespaces. Namespaces allow the use of the same name for two different objects in two different modules. Modules are organized into a visibility hierarchy so that each symbol defined in a module m is visible in modules that are children of m. |
Identifiers always belong to the namespace in which they are created (claire by default). The instruction module!() returns the module currently opened. To change to a new module, one may use begin(m:module) and end(m:module). The instruction begin(m) makes m the current module. Each newly created identifier (symbol) will belong to the module m, until end(m) resumes to the original module. For instance, we may define :
| begin(interface) window <: object(...) end(interface) |
The visibility rules among name spaces are as follows :
| begin(interface) window <: object(...) private/temporary <: window(...) end(interface) |
In practice, there is almost always a set of files that we want to associate with a module, which means that we want to load into the module's namespace. CLAIRE allows an explicit representation of this through the slots made_of and source. made_of(m) is the list of files (described as strings) that we want to associate with the module and source(m) is the common directory (also described as a string). The benefits are the load/sload methods that provide automatic loading of the module's files into the right namespace and the module compiling features. CLAIRE expects the set of file names to be different from module names, otherwise a confusion may occur at compile time.
A last important slot of a module is uses, a list of other modules that the new module is allowed to use. This list has two purposes, that only exist at compile time. The first one is to restrict the importation of symbols from other modules. A module is considered a legal import if it included itself in this uses list, or, recursively, if its father module is legal or if the module is legal for one of the modules in this list. An attempt to read a symbol m/s from a module that is not a legal import will provoke a compiler error. Second, this list is used by the compiler to find out which binaries should be included in the link script that is produced by the compiler.
| categories | Modules | normal dispatch | Kernel method |
Sets the current namespace to the module m.
| categories | Modules | normal dispatch | Kernel method |
Pop the current namespace and restore the namespace that was active before the call to begin(m).
| categories | Modules | normal dispatch | Kernel method |
module!() returns the current namespace (i.e. module).
| categories | Modules | normal dispatch | Kernel method |
module!(r) returns the module where the restriction r was created.