| A clear mechanism to structure large programs, the MINERVA packages
allow to
- incrementally compile large programs in units of files
- develop independent program parts with seperate name spaces
- load program parts automatically or on request
- build libraries of programs
- statically check for missing predicates
without extra effort by the MINERVA programmer.
Motivation
Large programs, teams of several programmers, maintenance needs
and software engineering discipline strongly suggest to break down
programs into manageable, fairly independent modules.
MINERVA supports this with seperate namespaces and an intelligent
loading scheme. This implements dynamically loadable modules
while still allowing fairly strict static checks by the compiler.
The overall result is smaller, faster loading and more robust programs.
Principles
The MINERVA compiler minervac produces for each
*.min MINERVA source file a *.mpk MINERVA package file
with the module interface specification
and a *.mbc MINERVA binary code file.
A program can access other packages with the package
directive.
Explicitly referenced predicates which are not defined in the
own program and not accessible via package directives are
flagged by the compiler with an error.
A program exports by default all its predicates.
Predicates starting with the underscore character '_' are not
exported to the *.mpk file and not accessible by other packages.
Predicates with identic name/arity exported by several
packages are shadowed by the predicate of the first
loaded package.
Packages are searched for in the directories and according to
the sequence given by the '-sp' parameter of minerva.
Even multiply referenced packages will be loaded only once.
Name spaces of seperate packages are seperate.
Examples
The package "aaa" exports aaa/1, aaa1/1, aaa2/1
but not _aaa3/3.
% file: aaa.min
aaa(C) :-
aaa1(A),
aaa2(B),
'_aaa3'(A,B,C).
aaa1(1).
aaa2(2).
'_aaa3'(A,B,C) :- C is A + B.
The package "bbb" can access all exported predicates from "aaa" and
exports bbb/1 but not _aaa3/3.
The definiton of bbb/1 uses _aaa3/3 of "bbb". _aaa3/3 of "aaa" is not
accessible to "bbb".
% file: bbb.min
:- package(aaa).
bbb(C) :-
aaa1(A),
aaa2(B),
'_aaa3'(A,B,C).
'_aaa3'(_,_,ccc).
"ccc" can access "bbb" and through "bbb" recursively "aaa".
"ccc" exports aaa/1.
If "ccc" is loaded first and then the result of ?- ccc(X). is
X = 1 because the definition of aaa/1 of "aaa" is accessible
to "ccc" but shadowed by the definition of aaa/1 of "ccc".
% file: ccc.min
:- package(bbb).
ccc(C) :-
aaa(C).
aaa(1).
Programing Recommendations
We recommend:
- to select an expressive name for each package,
if possible identic to the most prominent predicate defined
by that package.
This helps to understand program libraries.
- to mark internal predicates with the leading '_' as
non-top-level.
This keeps *.pkg files compact and stresses the
public predicates as intended for external use.
- to write the package directives at the top of a file.
This stresses program dependencies
- to use identic package search paths for both
compilation with minervac and execution with
minerva or over the net with the *.msp
MINERVA Startup Property file.
- to group independent libraries into seperate directories
and add these directories to the '-sp' search path option
of minerva and minervac as needed.
- to use the '-v' option of minerva to check the
loading sequence and timing of packages.
- to use the '-l' option of minerva to force
loading at startup time if desired.
- to use the 'load/1' predicate to force loading
at run time if desired.
- to use the automatic loading "on demand" mechanism of
MINERVA as default
|