Once a module is defined (see Writing modules) it can be accessed, provided it is within reach, using an access clause. The access clause identifies the modules to access and then makes the publicized definitions of these modules visible within a control clause.
For example, this is how we could use the logger definition module defined in a previous section to log the progress of some program that reads an input file and writes some output file:
access Logger
begin # Identify ourselves with the program name #
originator := argv (1);
# Read input file. #
if NOT parse_input (argv (2))
then log ("error parsing input file"); stop fi;
# Write output file. #
if NOT write_output (argv (3))
then log ("error writing output file"); stop fi;
log ("success")
end
In this case the controlled clause is the closed clause conforming the
particular program, and the definitions publicized by the logger
module, in this case originator and log, can be used
within it.
An access clause is not restricted to just provide access to a single module: any number of module indicators can be specified in an access clause. Suppose that our example processing program has to read and write the data in JSON format, and that a suitable JSON library is available in the form of a reachable module. We could then make both logger and json modules accessible like this:
access Logger, JSON
begin # Identify ourselves with the program name #
originator := argv (1);
JSONVal data;
# Read input file. #
if data := json_from_file (argv (2));
data = json no val
then log ("error parsing input file"); stop fi;
# Write output file. #
if not json_to_file (argv (3), data)
then log ("error writing output file"); stop fi;
log ("success")
end
In this version of the program the access clause includes the module
indicator json, and that makes the mode indicator
jsonval and the tags json no val, json
from file and json to file visible within the program’s
closed clause.
Note that the following two access clauses are not equivalent:
access Logger, JSON C ... C; access Logger access JSON C ... C;
In the first case, a compilation time error is emitted if there is a
conflict among the publicized definitions of both modules; for
example, if both modules were to publicize a procedure called
log. In the second case, the declaration of log
publicized by Logger would hide the declaration of
log publicized by JSON. This also has implications
related to activation, that we will be discussing in a later section.
The controlled clause in an access clause doesn’t have to be a serial clause, like in the examples above. It can be any enclosed clause, like for example a loop clause:
proc frobnicate frobs = ([]Frob frobs) void:
access Logger to UPB frobs
do log ("frobnicating " + name of frob);
frobnicate (frob)
od
The elaboration of an access clause yields a value, which is the value yielded by the elaboration of the controlled clause. Since the later is an enclosed clause, coercions get passed into them whenever required, the usual fashion.
We can see an example of this in the following procedure, whose body
is a controlled closed clause that yields a real value:
proc incr factor = (ref[]real factors, int idx) real:
access logger (log ("factor increased"); factors[idx] +:= 1.0)
Note how the access clause above is in a strong context requiring a
value of mode real. The value yielded by the access clause
is the value yielded by the controlled enclosed clause, which in this
case is a closed clause. The strong context and required mode gets
passed to the last unit of the closed clause (the assignation) which
in this case yields a value of mode ref real. The unit
is coerced to real by dereferencing, and the resulting
value becomes the value yielded by the access clause.
A definition module may itself access other modules. This is done by placing the module text as a controlled clause of an access clause. Suppose we rewrite our logger module so it uses JSON internally to log JSON objects rather than raw strings. We could do it this way:
module logger =
access json
def int fd = stderr;
pub string originator;
pub proc log = (string msg) void:
fputs (fd, json array (json string (originator),
json string (msg)));
log (json string ("beginning of log\n"));
postlude
log (json string ("end of log\n"));
fed
Note how this version of logger uses a few definitions
publicized by the json module.
A program accessing logger will not see the definitions
publicized by the json module. If that is what we
intended, for example to allow the users of the logger to tweak their
own JSON, we would need to specify it this way:
module logger = access pub json def c ...as before... c fed
In this version the definitions publicized by json become
visible to programs accessing logger.