Accessing modules (The GNU Algol 68 Compiler)

#### 2.2.2 Accessing modules ¶

Once a module is defined (see Writing modules) it can be accessed from other packets 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 particular 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.

#### 2.2.2.1 Accessing several modules ¶

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.

#### 2.2.2.2 The controlled clause ¶

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

#### 2.2.2.3 The value yielded by an access clause ¶

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.

#### 2.2.2.4 Modules accessing other modules ¶

Up to this point we have seen particular programs accessing modules, but 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`.