Go to the previous, next section.

The Module System

By making use of the module systems facilities, programs can be divided into different modules. Each module has its own independent predicate name space. This is an important feature for the development of larger programs. The module system of SICStus Prolog is procedure based. This means that only the predicates are local to a module, whereas terms are global. The module system is flat, not hierarchical, so all modules are visible to one another. It is non-strict, i.e. the normal visibility rules can be overridden by special syntax. No overhead is incurred on compiled calls to predicates in other modules. It is modeled after and compatible with the Quintus Prolog module system. Finally, using the module system is optional, and SICStus Prolog may be used without the user being aware of the module system at all.

Modules in SICStus Prolog can also be used for object-oriented programming. See section Prolog Objects for details.

Basic Concepts

Each predicate in the Prolog system, whether built-in or user defined, belongs to a module. A predicate is generally only visible in the module where it is defined. However a predicate may be imported by another module. It is thereby made visible in that module too. Built-in predicates are visible in every module. Predicates declared as public in a module declaration (see below) are exported. Normally only public predicates may be imported by another module.

For any given goal, the source module is the module in which the corresponding predicate must be visible. Similarly, for any given clause, the source module of its head is the module into which the clause is loaded.

For goals occurring in a source file with a module declaration, the source module is the declared module. For goals occurring in a source file without a module declaration, the source module is the module that the file is being loaded into. For goals typed at the top level, the source module is the type-in module. The type-in module is by default the user module but may be changed by the built-in predicate module/1.

The other predefined module is the prolog module where all the built-in predicates reside. The exported built-in predicates are automatically imported into each new module as it is created.

Module Prefixing

Notwithstanding the visibility rules, any predicate can be called from any other module by prefixing the goal with the module name and the colon operator, thus overriding the source module of the goal:

| ?- foo:bar(X).

This feature is intended mainly for debugging purposes, since it defies the purposes of the module system. If the prefixed goal is a meta-predicate, however, the prefixed module name may affect the module name expansion of the goal (see section Module Name Expansion).

It is also possible to override the source module of clauses and directives by module prefixing. For example,

:- dynamic mod:p/1.
p(X) :- mod:(q(X), r(X)).
mod:(q(X) :- r(X)).
mod:s(X) :- t(X).

declares mod:p/1 as dynamic, whatever the source module is; defines p/1 in the source module as calling mod:q/1 and mod:r/1; defines mod:q/1 as calling mod:r/1; and defines mod:s/1 as calling t/1 in the source module. The latter technique is particularly useful when the prefix is user and the predicate is a "hook" predicate such as user:portray/1 which must be defined in the user module, but the rest of the file consists of predicates belonging to some other module.

Defining Modules

A module is normally defined by putting a module declaration first in a source file.

:- module(ModuleName, PublicPredicateList).

When the file is loaded, all predicates in the file go into ModuleName and the predicates of the PublicPredicateList are exported. When a module declaration is processed, all existing predicates in the module are erased before the new ones are loaded. A file which contains a module declaration is henceforth called a module file.

A module can also be defined dynamically by asserting or loading predicates to it:

| ?- assert(m:p(x)).

creates the module m, if it does not already exists, and asserts p(x) to it.

| ?- compile(m:f).

creates the module m and loads f into m.

Dynamically created modules have no public predicates.

Importation

When a module file is loaded by one of the predicates consult/1, compile/1, ensure_loaded/1, use_module/1, or load/1 (See section Loading Programs), all the public predicates of the module file are imported by the receiving module. In addition, the built-in predicates use_module/(2-3) may be used to specify which predicates to import.

Clashes with already existing predicates, local or imported from other modules, are handled in two different ways: If the receiving module is the user module, the user is asked for redefinition of the predicate. For other receiving modules, a warning is issued and the importation is canceled. In the first case redefinition silently takes place if the flag redefine_warnings has the value off (see prolog_flag/3). The binding of an imported predicate remains, even if the origin is reloaded or deleted. However, abolish/1 breaks up the importation binding. When a module file is reloaded, a check is made that the predicates imported by other modules are still in the public list. If that is not the case, a warning is issued. Note that an imported predicate may be re-exported.

There is no error checking of module handling in Runtime Systems.

Module Name Expansion

Some predicates take goals as arguments (i.e. meta-predicates). These arguments must include a module specification stating which module the goal refers. Some other predicates also need module information i.e. compile/1. The property of needing module information is declared with a meta-declaration (see section Meta-Predicate Declarations). Goals for these predicates are module name expanded to ensure the module information. Goals issued at top level and goals appearing as directives are expanded prior to execution while goals in the bodies of clauses are expanded at compile time. The expansion is made by preceding the relevant argument with `Module:'. If the goal is prefixed by `Module:', Module is used for the expansion, otherwise the source/type-in module is used. An argument is not expanded if:

1. It already has a module prefix.
2. It is a variable which appears in an expandable position in the head of the clause.

Some examples:

| ?- [user].
| :- meta_predicate p(:), q(:).
| r(X) :- p(X).
| q(X) :- p(X).
| ^D
{user consulted, 40 msec 1088 bytes}

yes
| ?- listing.

r(A) :-
        p(user:A).

q(A) :-
        p(A).

yes

Here, p/1 and q/1 are declared as meta-predicates while r/1 is not. Thus the clause r(X) :- p(X) will be transformed to r(X) :- p(M:X), by item 2 above, where M is the type-in module, whereas q(X) :- p(X) will not.

| ?- m:assert(f(1)).

Here, assert/1 is called in the module m. However, this does not ensure that f(1) is asserted into m. The fact that assert/1 is a meta-predicate makes the system module name expand the goal, transforming it to m:assert(m:f(1)) before execution. This way, assert/1 is supplied the correct module information.

Meta-Predicate Declarations

The fact that a predicate needs module name expansion is declared in a meta-predicate declaration:

:- meta_predicate MetaPredSpec, @dots{}, MetaPredSpec.

where each MetaPredSpec is a mode spec. E.g.

:- meta_predicate p(:, +).

which means that the first argument of p/2 shall be module name expanded. The arguments in the mode spec are interpreted as:

@
@
This argument, in any call to the declared predicate, shall be expanded. (Integers are allowed for compatibility reasons).

@
This argument shall not be expanded

A number of built-in predicates have predefined meta-predicate declarations, as indicated by the mode specs in this manual, e.g. call(:Term).

Go to the previous, next section.