Modula-2

Modula-2
Paradigmen: imperativ, strukturiert, modular
Erscheinungsjahr: 1978
Designer: Niklaus Wirth
Entwickler: Niklaus Wirth
Beeinflusst von: Pascal
Beeinflusste: Lua, Oberon, Seed7, Modula-2+, Modula-3

Modula-2 ist eine 1978 entstandene Weiterentwicklung der Programmiersprache Pascal und wurde wie diese von Niklaus Wirth entwickelt. Hauptkennzeichen von Modula-2 sind die Sprachmerkmale zur Modularisierung von Programmen. Modula-2 selbst diente später als Vorlage für die Programmiersprache Oberon.

Entstehung

Wirth hatte 1977/78 am Forschungszentrum Palo Alto Research Institute von Xerox die zukunftsweisende Architektur der Alto-Workstations kennengelernt, die bereits über Maus, Grafikbildschirm und Fenstertechnik verfügten. Programmiert wurde der Alto in der Pascal-ähnlichen Programmiersprache Mesa. Nach seiner Rückkehr an die ETH Zürich begann Wirth mit seiner Gruppe die Eigenentwicklung einer solchen Workstation, der später so genannten Lilith, wobei Hardware und Software im Zusammenhang entwickelt wurden.

Standard-Pascal, das als Sprache für den Programmierunterricht entwickelt worden war, eignete sich nicht für die Programmierung eines Betriebssystems für die Lilith, und zwar vor allem aus zwei Gründen:

Die neue Sprache, die den Namen „Modula“ erhielt, enthielt gegenüber Pascal deshalb (neben etlichen Änderungen in der Syntax) zwei neue Konzepte:

Modula wurde außerhalb der ETHZ erst in der Version Modula-2 bekannt. Die klare Trennung von Definition und Implementierung in getrennten Dateien (in der Regel mit Extension DEF bzw. MOD) war richtungsweisend und wurde von späteren Programmiersprachen zwar kopiert, aber in ihrer Klarheit nicht erreicht. Modula-2 hatte später von Wirth unabhängige Nachfolger wie Modula-2 plus und Modula-3. Seit 1996 gibt es eine internationale Norm ISO/IEC 10514-1 für Modula-2.

Eigenschaften

Da Modula-2 eine Fortentwicklung von Pascal ist, genügt es, auf die wesentlichen Unterschiede zu dieser Sprache einzugehen.

Module

Die prominenteste Neuerung in Modula-2 sind die Module als Vorrichtung für das modulare Programmieren nach den Vorstellungen der Softwaretechnik, zuerst geäußert von David Parnas. Auch das Hauptprogramm heißt deswegen MODULE statt PROGRAM wie in Pascal. Alle separat vom Hauptprogramm übersetzten Teile müssen in zwei Dateien aufgespaltet werden: Ein DEFINITION MODULE enthält nur die Beschreibung der Schnittstelle des Moduls, das heißt: es listet die Konstanten, Typen, Variablen und Prozeduren auf, die für andere Module zur Verfügung gestellt („exportiert“) werden sollen. Ein getrenntes IMPLEMENTATION MODULE gibt dann die Implementierung an.

Es ist im Sinne der strikten Modularisierung folgerichtig, dass Konzepte wie die Ein-/Ausgabe und mathematische Funktionen, die in Pascal zum normalen Sprachumfang gehörten, in der Sprache Modula-2 nicht enthalten sind. Sie müssen im Bedarfsfall aus dafür vorgesehenen Modulen (in der Regel InOut für Ein-/Ausgabe und MathLib für die mathematischen Funktionen) importiert werden.

Datentypen

Die Lilith sollte eine Wortbreite von 16 bit bekommen. Ganze Zahlen hätten somit einen Bereich von -32.768 bis +32.767 gehabt, was Wirth als zu große Einschränkung empfand. Zusätzlich zum Datentyp INTEGER bekam Modula-2 daher einen Datentyp CARDINAL für die nicht-negativen Zahlen zwischen 0 und 65.535. Gemischte Ausdrücke, die sowohl INTEGER- als auch CARDINAL-Teilausdrücke enthalten, waren verboten. Deshalb gibt es allgemeine Möglichkeiten, Typen zu verwandeln:

  • Typkonversionsfunktionen VAL(Typ,Ausdruck) rechnen einen Ausdruck so um, dass er zu dem neuen Typ gehört, während
  • Typtransferfunktionen („type casts“, bei Wirth: „type cheats“) der Form Typ(Ausdruck) ein Bitmuster unverändert lassen und lediglich für den Compiler den Datentyp verändern.

Beispielsweise ergibt VAL(CARDINAL,-1) eine Fehlermeldung, während CARDINAL(-1) = 65.535 gilt.

Eine Innovation gegenüber Pascal stellt auch der Datentyp PROCEDURE dar, mit dem eine Schwäche von Pascal behoben werden sollte: In Pascal war es möglich, einer Prozedur eine Funktion als Argument zu übergeben, gekennzeichnet durch das Schlüsselwort FUNCTION. Dabei konnte jedoch nicht überprüft werden, ob die später aktuell übergebene Funktion in Anzahl und Typ ihrer Parameter überhaupt passend war. Deklariert man jedoch in Modula-2 beispielshalber

   TYPE myFunction = PROCEDURE (INTEGER): REAL;

so kann beim Aufruf einer Prozedur (das Schlüsselwort FUNCTION gibt es in Modula-2 nicht)

   PROCEDURE myProcedure (f: myFunction; n: INTEGER): REAL;

der Compiler bei jedem Aufruf von myProcedure feststellen, ob die aktuell für f übergebene Funktion den richtigen Typ hat. Da Prozeduren damit ganz normale Datentypen sind, ist es auch möglich, sie in anderen Datenstrukturen wie etwa ARRAYs und RECORDs einzubauen.

Kontrollstrukturen

Zur Vermeidung zahlreicher BEGINEND-Klammern wird in Modula-2 die IF- und WHILE-Anweisung jeweils mit einem END abgeschlossen. Das von Pascal vertraute GOTO gibt es nicht, dafür aber ein LOOPEXIT-Konstrukt.

Das Pseudomodul SYSTEM

Als Sprache für die Betriebssystemprogrammierung musste Modula-2 über Vorrichtungen verfügen, auf Details der zugrundeliegenden Maschine zuzugreifen. Dafür gab es ein eigenes Modul SYSTEM, aus dem sich die Datentypen WORD für ein unspezifisches Speicherwort und ADDRESS für eine Speicheradresse importieren ließen, ebenso wie eine Funktion ADR zur Ermittlung der Speicheradresse eines Konstrukts und TSIZE zur Ermittlung der Speichergröße für einen bestimmten Datentyp. Hinzu kommen die bereits erwähnten Funktionen für die nebenläufige Programmierung.

SYSTEM heißt Pseudomodul, weil es dazu weder Definitions- noch Implementierungsteil gibt, sondern alle Kenntnis über dieses Modul direkt in den Compiler eingebaut ist.

Entwicklung

Es gibt zwei Dialekte von Modula-2. Einerseits PIM, die von Niklaus Wirth entwickelten und im Standardwerk "Programmieren in Modula-2" definierten Varianten. Entsprechend den Auflagen des Buches gibt es die zweite, dritte und vierte Variante von PIM. Mit jeder Auflage wurde die Sprache leicht verändert. Der zweite Dialekt ist ISO, die von einem internationalen Komitee (unter dem Dach der International Organization for Standardization) erarbeitete Variante.

  • PIM2 (1983): Expliziter EXPORT in Definitionsmodulen.
  • PIM3 (1985): Kein expliziter Export in Definitionsmodulen mehr nötig.
  • PIM4 (1989): Konkretisierung des Verhaltens des MOD-Operators, wenn die Operanden negativ sind.
  • ISO (1996): Der Anspruch bei der Entwicklung von ISO Modula-2 war, die Mehrdeutigkeiten von PIM Modula-2 aufzulösen. Außerdem wurden der Sprache die Datentypen COMPLEX und LONGCOMPLEX, Ausnahmen (Exceptions), die Modultermination (FINALLY-Klausel) und eine umfangreiche Standardbibliothek für Ein- und Ausgabe hinzugefügt – neben einer Reihe von kleineren Änderungen.[1]

Implementierungen

Modula-2 erreichte in den späten 1980er Jahren eine verhältnismäßig große Popularität, insbesondere in der Version von Jensen und Partners International (JPI), die einen 10-Fenster-Editor in ihrer Entwicklungsumgebung für MS-DOS und einen sehr schnellen Compiler mit gut optimiertem Objektcode auf den Markt brachten. Spätere Versionen davon hießen TopSpeed Modula-2; in die Entwicklungsumgebung wurden auch C und C++ aufgenommen.

Aktuelle Modula-2-Compiler:

Kritik

Wirth selbst[2] listet im Zusammenhang mit der Entwicklung von Oberon folgende Probleme von Modula-2 auf:

Qualifizierende Importe

Die empfohlene Methode zur Verwendung von Bestandteilen fremder Module ist

IMPORT M;

Dadurch werden alle von M exportierten Bezeichner durch sogenannte qualifizierte Bezeichner, etwa M.A, M.B verfügbar. Alternativ dazu kennt Modula-2 den qualifizierenden Import

FROM M IMPORT A,B;

Bei diesem Import sind die Bezeichner dann einfach in der Form A bzw. B verfügbar; die Herkunft aus dem Modul M ist an der Verwendungsstelle dann nicht mehr direkt sichtbar. Dadurch können Programmierer Irrtümer begehen. In Oberon gibt es den qualifizierenden Import deshalb nicht mehr.

Export von Aufzählungstypen

Enthält ein Modul den exportierten Typ

TYPE Ampel = (rot, gelb, gruen);

so bezieht sich nach der Logik der Sprache ein Import dieses Typs nur auf den Typnamen (Ampel), in Wirklichkeit werden aber die Namen rot, gelb und gruen mitimportiert, was im Falle von Bezeichnerkonflikten an der Verwendungsstelle den Programmierer verwirren kann. In Oberon gibt es Aufzählungstypen deshalb gar nicht mehr, weil man sonst auch ihren Export nicht verhindern könnte.

Datentyp CARDINAL

Vorzeichenlose Arithmetik funktioniert ganz anders als vorzeichenbehaftete Arithmetik; deshalb sind Ausdrücke, in denen vorzeichenlose und vorzeichenbehaftete Werte gleichzeitig vorkommen, problematisch. Modula-2 hat deshalb solche Mischungen grundsätzlich verboten, was bei den Programmierern auf Protest stieß, weil die Programme durch die Verwendung von Typkonversionsfunktionen unnötig verkompliziert wurden. Darüber hinaus entstehen Unsymmetrien in der Behandlung bestimmter Programmstrukturen und bei der mathematischen Modulo-Funktion (MOD).

Typtransferfunktionen und andere low level-Vorrichtungen

Mit den Typtransferfunktionen (type casts) wird es möglich, Eigenschaften der zugrundeliegenden Maschine zu entdecken, die dem Programmierer einer höheren Programmiersprache eigentlich verborgen bleiben sollten, wie etwa die Endianness, das heißt die Frage, in welcher Ordnung die einzelnen Bits eines Maschinenworts abgespeichert sind. Je nachdem ist nämlich

BITSET(65520) = {4 .. 15}

oder

BITSET(65520) = {0 .. 11}

für eine 16-Bit-Architektur.

Literatur

Einzelnachweise

  1. ISO/IEC 10514-1:1996
  2. A Brief History of Modula and Lilith. In: Advances in Modular Languages – Proceedings of the Joint Modular Languages Conference, Ulm 1994