16.4 Refining Within a Program Module

Besides refining a generic separate module as a refined separate module, it is also possible to refine as a local module. A refining local module is similar to a local module in the sense of the base language, and the rules for local modules given in the base standard apply, with the following change.

The syntax of a refining local module is even simpler than that of a refining separate module. It consists of the word MODULE followed by the name to be given to the resulting (refined) module, then an equal sign, and then the formal parameter list. To be consistent with the rest of Modula-2, it concludes with an END and a repetition of the name of the module. This is shown in figure 16.5.

NOTE : The identifier of the generic separate module named in the refining local module declaration must be visible in the scope of the refining local module. This means that it will have to be named in an import statement in the enclosing module

Refinement of generic separate modules as local modules is similar to refinement as separate modules in that:

However, there are some differences. A local module has only one part (not a separate definition and implementation). Thus, the result of refining locally has to be some combination of the results of refining as separate modules. The interpretation of the refinement of a generic separate module as a local module is that:

  1. The refinement is the merger of the refinements of the library definition and implementation module pair of the generic separate module (the name of which must be visible at the place of the refinement.)
  2. The list of exports of the refined local module into its surrounding scope is specified in the refining local module. Because these exports may be qualified, two refinements (under different names) of the same generic separate module could both be made in one scope without causing a name clash.
  3. Such a merger only makes sense if the parameter lists of the definition and implementation parts of the generic separate module are the same, and this is one of the reasons why the standards committee adopted this rule.
  4. If the implementation part of a generic separate module contains a refining local module, that refining local module cannot refine from the same generic separate module in which it is contained‹whether directly or indirectly. That is, recursive refinement is not permitted.
  5. The translator shall be able to detect a new syntax error, for it is not possible to use (apart from refinement) items from a generic separate module directly in another module. For instance, if one were to import for the purpose of local refinement the module Sorts, a use of Sorts.Quick is invalid.
  6. In such a case, the name Sorts does have to be imported into the scope of the refinement, however. This import provides only the name of the module, not the names of any items in it. The latter must be refined to be used.

Example 1: What follows is a sketch of a program client containing two local refinements of the first example in section 16.2.1

MODULE StackClient;
IMPORT Stacks; (* the generic name has to be imported *)

TYPE  
  RecDef =
    RECORD
     c : CHAR;
     i : INTEGER
    END (* record *);
            
MODULE CardStack = Stacks (CARDINAL);
EXPORT QUALIFIED StackSize, Push, Pop, Empty;
END CardStack;

MODULE RecStack = Stacks (RecDef);
EXPORT StackSize, Push, Pop, Empty;
END RecStack;
  
VAR
  c : CARDINAL;
  r : RecDef;  

BEGIN (* main *)
  CardStack.Push (c);
  Push (r);
END StackClient.

On the one hand, the refinement of the local modules of this module has to export according to the export list in the refiner, and on the other hand it must consist of the merger of the corresponding definition and implementation parts of the generic separate modules. This means, for instance, that the refiner can only export items that are in the definition module of the generic separate module from which it is refining. However, it can export those items either qualified or unqualified, and it need not export them all.

Example 2: The generic matrices defined in example 2 of section 16.2.1 may be refined locally using literal or constant data established in the main module.

MODULE Client;

IMPORT Matrix;

  MODULE Mat10x20 = Matrix (10, 20, CARDINAL);
  EXPORT QUALIFIED TMatrix, Invert;
  END Mat10x20;

CONST
  row = 4;
  col = 6;

  MODULE MatRowXCol = Matrix (row, col, CARDINAL);
  EXPORT QUALIFIED TMatrix, Invert;
  END MatRowXCol;

VAR
  m : Mat10x20.TMatrix;
  n : MatRowXCol.TMatrix;

BEGIN
  (*.
    .
    .*)
  Mat10x20.Invert (m);
  MatRowXCol.Invert (n);
END Client.

Example 3: Two independent local refinements of the module counter in example 5 of section 16.2.1 may be performed, in effect creating two ADT counters both of which are hidden from the program and modifiable only through the refined procedures.

MODULE NeedsACounter;

IMPORT Counter;

VAR
  countingCondition1, countingCondition2 : BOOLEAN;
  
MODULE Duke = Counter;
EXPORT QUALIFIED Inc, Reset, Count;
END Duke;

MODULE Baron = Counter;
EXPORT QUALIFIED Inc, Reset, Count;
END Baron;

BEGIN (* main program module *)

IF countingCondition1 
  THEN
    Duke.Inc;
  ELSIF countingCondition2 THEN
    Baron.Inc;
  END;

END NeedsACounter.

Contents