The module system

Author(s): Daniel Cabeza, The CLIP Group.

Modularity is a basic notion in a modern computer language. Modules allow dividing programs in several parts, which have its own independent name spaces. The module system in Ciao [CH00a], as in many other Prolog implementations, is procedure based. This means that predicate names are local to a module, but functor/atom names in data are shared (at least by default).

The predicates visible in a module are the predicates defined in that module, plus the predicates imported from other modules. Only predicates exported by a module can be imported from other modules. The default module of a given predicate name is the local one if the predicate is defined locally, else the last module from which the predicate is imported, where explicit imports have priority over implicit ones (that is, a predicate imported through a use_module/2 declaration is always preferred over a predicate imported through a use_module/1 declaration). To refer to a predicate from a module which is not the default module for that predicate the name has to be module qualified. A module qualified predicate name has the form Module:Predicate as in the call debugger:debug_module(M). Note that in Ciao this module qualification cannot be used for gaining access to predicates that have not been imported, nor for defining clauses of other modules.

All predicates defined in files with no module declaration belong to a special module called user, from which they are all implicitly exported. This provides backward compatibility for programs written for implementations with no module system and allows dividing programs into several files without being aware of the module system at all. Note that this feature is only supported for the above-mentioned backward-compatibility reasons, and the use of user files is discouraged. Many attractive compilation features of Ciao cannot be supported for user modules.

The case of multifile predicates (defined with the declaration multifile/1) is also special. Multifile predicates can be defined by clauses distributed in several modules, and all modules which define a predicate as multifile can use that predicate. The name space of multifile predicates is independent, as if they belonged to the special module multifile.

Every user or module file imports implicitly a number of modules called builtin modules. They are imported before all other importations of the module, thus allowing the redefinition of any of their predicates (with the exception of true/0) by defining local versions or importing them from other modules. Importing explicitly from a builtin module, however, disables the implicit importation of the rest (this feature is used by package library(pure) to define pure Prolog code).

Usage and interface

  • Library usage:
    Modules are an intrinsic feature of Ciao, so nothing special has to be done to use them.

Documentation on internals

DECLARATION

Usage: :- module(Name,Exports,Packages).

  • Description: Declares a module of name Name which exports the predicates in Exports, and uses the packages in Packages. Name must match with the name of the file where the module resides, without extension. For each source in Packages, a package file is used. If the source is specified with a path alias, this is the file included, if it is an atom, the library paths are searched. See package/1 for a brief description of package files.

    This directive must appear the first in the file.

    Also, if the compiler finds an unknown declaration as the first term in a file, the name of the declaration is regarded as a package library to be included, and the arguments of the declaration (if present) are interpreted like the arguments of module/3.

  • The following properties hold at call time:
    (modules:modulename/1)Name is a module name (an atom).
    (basic_props:list/2)Exports is a list of prednames.
    (basic_props:list/2)Packages is a list of sourcenames.

DECLARATION

Usage: :- module(Name,Exports).

  • Description: Same as directive module/3, with an implicit package default. This default package provides all the standard features provided by most Prolog systems so that Prolog programs with traditional module/2 declarations can run without any change.
  • The following properties hold at call time:
    (modules:modulename/1)Name is a module name (an atom).
    (basic_props:list/2)Exports is a list of prednames.

DECLARATION

Usage: :- package(Name).

  • Description: Declares a package of name Name. Like in modules, Name must match with the name of the file where the package resides, without extension. This directive must appear the first in the file.

    Package files provide syntactic extensions and their related functionalities by defining operators, new declarations, code translations, etc., as well as declaring imports from other modules and defining additional code. Most Ciao syntactic and semantic extensions, such as functional syntax, constraint solving, or breadth-first search are implemented as packages.

  • The following properties hold at call time:
    (modules:modulename/1)Name is a module name (an atom).

DECLARATION

Usage 1: :- export(Pred).

  • Description: Adds Pred to the set of exported predicates.
  • The following properties hold at call time:
    (basic_props:predname/1)Pred is a Name/Arity structure denoting a predicate name:
    predname(P/A) :-
            atm(P),
            nnegint(A).
    

Usage 2: :- export(Exports).

  • Description: Adds Exports to the set of exported predicates.
  • The following properties hold at call time:
    (basic_props:list/2)Exports is a list of prednames.

DECLARATION

Usage: :- use_module(Module,Imports).

  • Description: Specifies that this code imports from the module defined in Module the predicates in Imports. The imported predicates must be exported by the other module.
  • The following properties hold at call time:
    (streams_basic:sourcename/1)Module is a source name.
    (basic_props:list/2)Imports is a list of prednames.

DECLARATION

Usage: :- use_module(Module).

  • Description: Specifies that this code imports from the module defined in Module all the predicates exported by it. The previous version with the explicit import list is preferred to this as it minimizes the chances to have to recompile this code if the other module changes.
  • The following properties hold at call time:
    (streams_basic:sourcename/1)Module is a source name.

DECLARATION

Usage: :- import(Module,Imports).

  • Description: Declares that this code imports from the module with name Module the predicates in Imports.

    Important note: this declaration is intended to be used when the current module or the imported module is going to be dynamically loaded, and so the compiler does not include the code of the imported module in the current executable (if only because the compiler cannot know the location of the module file at the time of compilation). For the same reason the predicates imported are not checked to be exported by Module. Its use in other cases is strongly discouraged, as it disallows many compiler optimizations.

  • The following properties hold at call time:
    (modules:modulename/1)Module is a module name (an atom).
    (basic_props:list/2)Imports is a list of prednames.

DECLARATION

Usage: :- reexport(Module,Preds).

  • Description: Specifies that this code reexports from the module defined in Module the predicates in Preds. This implies that this module imports from the module defined in Module the predicates in Preds, an also that this module exports the predicates in Preds .
  • The following properties hold at call time:
    (streams_basic:sourcename/1)Module is a source name.
    (basic_props:list/2)Preds is a list of prednames.

DECLARATION

Usage: :- reexport(Module).

  • Description: Specifies that this code reexports from the module defined in Module all the predicates exported by it. This implies that this module imports from the module defined in Module all the predicates exported by it, an also that this module exports all such predicates .
  • The following properties hold at call time:
    (streams_basic:sourcename/1)Module is a source name.

DECLARATION

Usage: :- meta_predicate MetaSpecs.

  • Description: Specifies that the predicates in MetaSpecs have arguments which has to be module expanded (predicates, goals, etc). The directive is only mandatory for exported predicates (in modules). This directive is defined as a prefix operator in the compiler.
  • The following properties hold at call time:
    (basic_props:sequence/2)MetaSpecs is a sequence of metaspecs.

REGTYPE
A module name is an atom, not containing characters `:' or `$'. Also, user and multifile are reserved, as well as the module names of all builtin modules (because in an executable all modules must have distinct names).

Usage: modulename(M)

  • Description: M is a module name (an atom).

REGTYPE
A meta-predicate specification for a predicate is the functor of that predicate applied to terms which represent the kind of module expansion that should be applied to each argument. Possible contents are represented as:

?,+,-,_
These values denote that this argument is not module expanded.

goal
This argument will be a term denoting a goal (either a simple or complex one) which will be called. For commpatibility reasons it can be named as : as well.

clause
This argument will be a term denoting a clause.

fact
This argument should be instantiated to a term denoting a fact (head-only clause).

spec
This argument should be instantiated to a predicate name, as Functor/Arity.

pred(N)
This argument should be instantiated to a predicate construct to be called by means of a call/N predicate call (see call/2).

list(Meta)
This argument should be instantiated to a list of terms as described by Meta (e.g. list(goal)).

addterm(Meta)
This argument should be instantiated to the meta-data specified by Meta, and an argument added after this one will carry the original data without module expansion. Not intended to be used by normal users.

addmodule(Meta)
This argument should be instantiated to the meta-data specified by Meta, and in an argument added after this one will be passed the calling module, for example to allow handling more involved meta-data by using conversion builtins. addmodule is an alias of addmodule(?). Not intended to be used by normal users.

Usage: metaspec(M)

  • Description: M is a meta-predicate specification.