6.2 Libraries--How to Borrow a Module and Sign it Out

Certain tools (input/output, for example) are needed in any programming environment in order to create useful code. From the very first program module presented in chapter two, this text has made use of some of the many modules that are available as part of a typical Modula-2 system. These contain a variety of entities that can be imported into a program without having to be re-written every time they are needed.

When Niklaus Wirth defined the Modula-2 notation, he was, for the most part, quite clear and specific about the way its various elements were to be used, and how they would behave. However, when it came to the libraries, he suggested rather than legislated. Thus, for instance, the input/output modules that appear in his book are described as "typical." Wirth says:

"We postulate some operations that are to be available in every implementation of Modula, although we wish to specify rigidly neither the names of the modules containing them nor the set of remaining operations included in these modules." Programming in Modula-2, third edition p.105

He went on to describe the module InOut as one of these typical modules, and to make suggestions for several others as well. Because these were only suggestions, they were not always followed by implementors. For instance, although the functionality of a WriteInt was always needed, it was not always supplied by vendors in the same way. Likewise, there is always a ReadString, but the name of the module from which it was imported may vary. In the case of WriteReal, even the syntax often varies, as has been seen already in this text. In the absence of any other guidance, however, and because the first compilers were produced by Wirth himself and then licensed to commercial vendors, most early implementations of Modula-2 had a very similar core library.

The (classical standard) Modula-2 library is a collection of previously defined modules whose entities form a part of the operating environment of Modula-2. These are not a part of the language proper (i.e. neither reserved words nor standard identifiers), but are available for import by other modules.

The many variations in interpretation even of details of the language, and the limitations and inconsistencies in the various implementations of these suggested I/O libraries were part of the motivation that led to the formation of the ISO standards committee in 1987. It was charged with the production of an international standard for the language, and also with the definition of a standard set of library modules. The latter had reached what appeared to be a final form by 1992, and most implementations provided the new libraries by 1996 when the standard became official.

The (ISO standard) Modula-2 library is a collection of previously defined modules whose entities form a part of the operating environment of Modula-2. These are not a part of the language proper (i.e. neither reserved words nor standard identifiers), but are available for import by other modules. All versions of Modula-2 claiming compliance with the ISO standard and requiring the functionality of one of these libraries (input and output, for instance) must provide that library exactly as specified in the standard, with no additions, deletions, or changes in meaning.

Even though the ISO library has been widely adopted, the older classical core library is still supplied by some vendors, for compatibility with older code.

The case of input and output is a particularly difficult one to deal with, because every computer system in which a programmer works may handle these things differently. That is the reason why standard input and output are not handled as built-ins, but are found in the library. This is done in order to keep the language itself both small and more portable across many systems.

STextIO, SRealIO, and SWholeIO (or InOut and RealInOut) form a suite of high level modules, in the sense that their facilities can be used by a program without regard to very many system details. At some point, however, they must in turn call on lower level code (to access data streams, for instance) in order to translate standard procedure invocations into something the particular system can use. That is, there is a hierarchical ordering of the modules involved in I/O, with the higher ones the most general and furthest abstracted from the actual system, and the lowest ones the most detailed and system specific. Naturally, a programmer who desires to do the extra work required can tap into this hierarchy at a lower level lower to define different styles of or destinations for input and output than those used by the highest level modules.

The lower one goes in this hierarchy, the more power that is gained, but the modules also become progressively harder to use. Again, here is a flexibility not available in other languages; one could implement entirely different WriteCard or WriteString procedures than the ones provided if this were thought desirable. The details of this organization are not essential to a beginning programmer and a good Modula-2 implementation will hide most of this detail away from beginning programmers so only those who have become more skilled can take advantage of some of the lower-level library modules. More detail will be provided on these lower level modules in later chapters; in section three of this one high level I/O will be more fully described.

Besides those for I/O, there are a number of other modules available in the standard library. All one has to know in order to use any of them is:

1. the name of the module containing the entity
2. the name of the entity
3. the correct syntax for using the entity, that is
- if a procedure, what are the types of the parameters?
- if a data type, what is its structure?
- if a variable, what are its allowed values?

In other words, one can treat standard library entities almost as if they were extensions of the language. Any library entities known to be available can be treated as extensions of a program. Once one knows they are there, one may just write:

  FROM FantasticModule IMPORT
    GreatRoutine, SuperVariable, MagicType;


  IMPORT FantasticModule

and then use them in ones own program module. In the latter case, the entity names must be qualified by the module name whenever they are referred to, and this may be necessary to avoid name conflicts, or to conform to local style rules. These methods apply both to existing library modules supplied by the vendor of the Modula-2 implementation, and to any that the programmer might write for private use.

User-designed modules are covered in section five of this chapter. The next two sections contain an examination of most of the higher level modules in the standard library, first considering I/O routines, and then some of the others.