To this point, examples have imported from no more than two or three modules. Some programs import from twenty or thirty, and some programmers get to know the contents of those modules very well as their programs grow longer. In addition, there will occasionally be an identifier of the same name in two different library modules. One cannot import both of these, as they have the same name. That would amount to declaring two different variables with the same name--something the compiler forbids, of course. In order to use both these identifiers in a program, one must first include in the import section of the module the line:
This is a different kind of import and requires one to adopt a slightly different style of documenting and using imported items. Instead of writing
FROM STextIO IMPORT WriteString, WriteLn;
FROM SWholeIO IMPORT WriteInt, WriteCard;
and referring to the imported identifiers as WriteString, WriteLn, WriteInt, and WriteCard, one may instead write the imports as:
IMPORT STextIO; IMPORT SWholeIO;
If this is done, the program has access to the entire contents of the imported module, but must refer to the items in them by also using the module name, in the manner of the following code:
STextIO.WriteString ("The results are:"); STextIO.WriteLn; SWholeIO.WriteInt (theInt,5) SWholeIO.WriteCard (theCard, 6)
and likewise for any other items in these or other library modules.
An identifier that is constructed from the name of the entity that owns it, followed by a period, followed by its own name, is called a qualified identifier.
An identifier that is referred to by its name alone is said to be unqualified.
Whenever this is done, any items belonging to the imported module become available for use in the importing module, provided their own names are qualified by their module name, as: ModuleName.itemFromModule. Since it may not be necessary to refer to all the identifiers of such a library in a qualified manner, it is permitted to do both styles of importing from the same module in one program.
NOTE: Programming notations other than Modula-2 may not allow both qualified and unqualified imports from the same library. They may not even have both in the language.
This new syntax forces a revision to the diagram of the import as shown in figure 3.7:
For example, the simple high level I/O libraries sketched by Wirth in Programming in Modula-2 and variously implemented by a number of manufacturers since, had a global variable Done in both InOut and RealInOut for checking the validity of Readxx operations. As these traditional modules (in some variation) are usually provided, the following non-standard example may provide a useful illustration:
Write a program to raise a real number to a cardinal power. Ensure that the data read from the user is correct before starting the calculations.
The Done variables will be used to check input validity, and the user will not be permitted to go on if the data is incorrect. To achieve this, an error message will be given and a retry allowed. However, only two tries will be allowed in each category.
MODULE CardPowerOfReal; (* non-ISO standard *) (* Written by R.J. Sutcliffe *) (* to illustrate qualified import *) (* using Metrowerks Modula-2 for the Macintosh computer *) (* last revision 1993 02 16 *) (* This non-standard program Module will request from its users a real and a cardinal and will raise the first number to the power of the second. Note that this is not a very efficient method of doing this; this topic will be returned to. *) FROM InOut IMPORT ReadCard, WriteString, WriteLn, Done, Read; IMPORT RealInOut; FROM RealInOut IMPORT ReadReal, WriteReal; CONST maxTries = 2; (* typing errors not allowed to go on forever *) VAR baseNumber, result : REAL; exponent, count, retries : CARDINAL; again, cardOK : BOOLEAN; answer, cr : CHAR; BEGIN WriteString ("This program raises real numbers to cardinal powers."); WriteLn; REPEAT (* main program repeat loop *) retries := 0; REPEAT (* trying to get a valid real for the base *) WriteString ("Type in a Real ===> "); ReadReal (baseNumber); Read (cr); (* get carriage return too *) IF NOT RealInOut.Done (* note how this is referred to*) THEN WriteString ("Incorrectly typed real"); WriteLn; retries := retries + 1; END; UNTIL RealInOut.Done OR (retries = maxTries); IF RealInOut.Done (* else, loop finishes; too much bad data *) THEN retries := 0; REPEAT (* trying to get valid cardinal for the exponent *) WriteString ("Type in a Cardinal ===> "); ReadCard (exponent); cardOK := Done; Read (cr); (* get carriage return too *) IF NOT cardOK (* unqualified IMPORT reference *) THEN WriteString ("Incorrectly typed cardinal"); WriteLn; retries := retries + 1; END; (* if not cardOK *) UNTIL cardOK OR (retries = maxTries); IF cardOK (* else, loop finishes; too much bad data *) THEN result := 1.0; (*initialize answer *) count := 1; WHILE count <= exponent DO (* multiply base by itself enough times *) result := result * baseNumber; count := count + 1; END; (* while *) WriteString ("The answer is "); WriteReal (result, 10); WriteLn; END; (* if Done *) END; (* if RealInOut.Done *) WriteString ("Do you want to do another one? "); Read (answer); Read (cr); (* knock the carriage return after the char off *) WriteLn; again := CAP (answer) = 'Y'; UNTIL NOT again; END CardPowerOfReal.
NOTE: The variable cardOK was employed because the Read following the ReadCard also resets Done. The behaviour of Done in such respects varies considerable from one version of non-ISO Modula-2 to another--a good reason to read the documentation carefully, or use a standard (predictable) version.
Here is a run from this program with user input indicated in bold.
This program raises real numbers to cardinal powers. Type in a Real ===> 2.5 Type in a Cardinal ===> 4 The answer is 39.06250 Do you want to do another one? y Type in a Real ===> a Incorrectly typed real Type in a Real ===> a Incorrectly typed real Do you want to do another one? y Type in a Real ===> 3.75 Type in a Cardinal ===> t Incorrectly typed cardinal Type in a Cardinal ===> y Incorrectly typed cardinal Do you want to do another one? y Type in a Real ===> 4.56 Type in a Cardinal ===> 7 The answer is 40997.17 Do you want to do another one? n
Notice how the various features of the program were all tested to ensure that the error trapping was operating as required.