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:
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.