Symbols categories
I/O, Modules and System Interface
Modules
Global Variables and Constants

Modules

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 = libraryuses = list(claire))
defines interface as a new sub-module to the library module that uses the module claire (which implies using all the modules). All module names belong to the claire namespace (they are shared) for the sake of simplicity.

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)
This creates the identifier interface/window. Each identifier needs to be preceded by its module, unless it belongs to the current module or one of its descendent, or unless it is private (cf. visibility rules). We call the short form "window" the unqualified identifier and the long one "interface/window" the qualified identifier.

The visibility rules among name spaces are as follows :

Any identifier can be made private when it is defined by prefixing it with private/. For instance, we could have written :
 begin(interface)
 window <: object(...)
 private/temporary <: window(...)
 end(interface)
The declaration private/temporary makes "temporary" a private identifier that cannot be accessed outside the module interface (or one of its descendents). The declaration claire/window makes window an identifier from the claire module (thus it is visible everywhere), which is allowed since claire belongs to the list of usable modules for 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 Modulesnormal dispatch Kernel method

begin(m:module) -> void

Sets the current namespace to the module m.


categories Modulesnormal dispatch Kernel method

end(m:module) -> void

Pop the current namespace and restore the namespace that was active before the call to begin(m).


categories Modulesnormal dispatch Kernel method

module!() -> module

module!() returns the current namespace (i.e. module).


categories Modulesnormal dispatch Kernel method

module!(r:restriction) -> module

module!(r) returns the module where the restriction r was created.