Programmiersprache Pascal

Evolution der Datentypkonzepte an einem Beispiel

Am Beispiel des Umgangs mit Datums- und Zeitinformationen soll gezeigt werden, welche Konzepte es im Umgang mit Daten gibt und wie diese sich entwickelt haben.


Version 1

Bei der Angabe eines Datum werden meist mitgeteilt:

Häufig werden Tag, Monat und Jahr als ganze Zahlen angegeben.

In einem Programm können Variablen vereinbart werden, die zur Aufbewahrung dieser Informationen dienen:

  VAR tag, monat, jahr : INTEGER;

  tag := 26; monat := 8; jahr := 1995;
Die Festlegung des einheitlichen Datentyps INTEGER ignoriert, daß die Angaben für Tag, Monat und Jahr nicht austauschbar sind. Für den Umgang mit ihnen gelten unterschiedliche Regeln.


Version 2

Durch die Einführung neuer Datentypen kann transparenter gemacht werden, daß Tag, Monat und Jahr zwar in einheitlicher Form als ganze Zahlen abgespeichert werden, daß sie aber ansonsten eine unterschiedliche Bedeutung haben.

  TYPE day = INTEGER;
       month = INTEGER;
       year = INTEGER;

  VAR tag : day;
      monat : month;
      jahr : year;

  tag := 26; monat := 8; jahr := 1995;
Zuweisungen der Form
  monat := tag;
sind danach in Sprachen, die wie Pascal dem Konzept der Namensäquivalenz folgen, nicht mehr zulässig.

Die Festlegung des Basisdatentyps INTEGER ignoriert jedoch, daß für Tag, Monat und Jahr keineswegs beliebige ganze Zahlen zulässig sind.


Version 3

Der Wertebereich für Tag, Monat und Jahr läßt sich mit Hilfe von Teilbereichstypen einengen.

  TYPE day = 1..31;
       month = 1..12;
       year = 0..2000;

  VAR tag : day;
      monat : month;
      jahr : year;

  tag := 26; monat := 8; jahr := 1995;
Zuweisungen der Form
  monat := 13;
sollten danach vom Sprachübersetzer als unzulässig zurückgewiesen werden.
Bei Zuweisungen der Form
  monat := function(...);
können unzulässige Wertzuweisungen nicht vom Sprachübersetzer erkannt werden. Ob sie zur Laufzeit des Programms signalisiert werden, hängt vom jeweiligen Programmiersystem und meist auch von den gesetzten Optionen ab, durch die das Laufzeitverhalten des Programms beeinflußt werden kann.
Es ist damit zu rechnen, daß im Standardfall aus Effektivitätsgründen (erhöhter Speicherplatz- und Laufzeitbedarf) auf die Prüfung von Laufzeitfehlern der obigen Form verzichtet wird.

Bemerkungen:
Turbo Pascal akzeptiert im Standardfall die Zuweisung

  monat := jahr;
Bei der obigen Wertbelegung gibt es einen Laufzeitfehler, falls die Option $R+ gesetzt wird.


Version 4

In vielen Fällen ist es wünschenswert, Datumsinformationen in kompakter Form weiterzugeben. Eine in Programmiersprachen schon lange verfügbare Möglichkeit der Zusammenfassung von Daten bieten Arrays.

  TYPE date = ARRAY[0..2] OF INTEGER;

  VAR datum : date;

  datum[0] := 26; datum[1] := 8; datum[2] := 1995;
Die Lesbarkeit des Programms ist jedoch bei dieser Version nicht ideal, es ist dem Leser keineswegs sofort klar ist, daß datum[0] den Tag, Datum[1] den Monat und datum[2] das Jahr beeinhalten.


Version 5

Mit Hilfe sogenannter Aufzählungstypen ist es in einer Reihe von Fällen möglich, die Lesbarkeit von Programmquelltext zu verbessern.

  TYPE index = (day, month, year);
       date = ARRAY[index] OF INTEGER;

  VAR datum : date;

  datum[day] := 26; datum[month] := 8; datum[year] := 1995;
Arrays gestatten nur die Aggregation von Werten mit gleichem Basisdatentyp. Die differenzierte Betrachtung der Datumskomponenten, die in den Versionen 2 und 3 bereits erreicht wurde, geht hier also wieder verloren.


Version 6

Moderne Programmiersprachen stellen für Situationen, in denen relativ wenige Werte, die sich in ihrem Datentyp unterscheiden können, aggregiert werden sollen, einen geeigneten Mechanismus bereit: den Verbund (Record).

  TYPE date = RECORD
                day : 1..31;
                month : 1..12;
                year : 0..2000;
              END;

  VAR datum : date;

  datum.day := 26; datum.month := 8; datum.year := 1995;

Version 7

Soll zusätzlich zu Tag, Monat und Jahr noch der Wochentag abgespeichert werden, so kann dies wie folgt realisiert werden:

  TYPE weekdays = (monday, tuesday, wednesday, thursday, friday, 
                           saturday, sonday);
       datew = RECORD
                 day : 1..31;
                 month : 1..12;
                 year : 0..2000;
                 day_of_the_week : weekdays;
               END;

  VAR datumw : datew;

  datumw.day := 26; datumw.month := 8; datumw.year := 1995;
  datumw.day_of_the_week := saturday;
Der Datentyp datew unterscheidet sich vom Datentyp datum nur durch eine zusätzliche Komponente.
Läßt sich in diesem Zusammenhang datew nicht effektiver unter Rückgriff auf date deklarieren ?

Dies ist in Turbo Pascal realisierbar:

  TYPE weekdays = (monday, tuesday, wednesday, thursday, friday,
                   saturday, sonday);
 
       date  = OBJECT
                 day : 1..31;
                 month : 1..12;
                 year : 0..2000;
               END;

       datew = OBJECT(date)
                 day_of_the_week : weekdays;
               END;

  VAR datumw : datew;

  datumw.day := 26; datumw.month := 8; datumw.year := 1995;
  datumw.day_of_the_week := saturday;
Realisiert wird dies durch eine Typerweiterung:
datew wird als Erweiterung von date deklariert und erbt alle Komponenten dieses Datentyps.

Syntaktisch wird dies in Turbo Pascal durch eine "entartete" Objekttypdeklaration umgesetzt: Objekte besitzen Daten und Methoden, die über diesen Daten operieren; Methoden fehlen hier jedoch.


Version 8

Für eine Reihe von Fällen wäre es sinnvoll, die Datumsvariable mit dem aktuellen Datum belegen zu können. In Turbo Pascal kann unter Verwendung einer vordefinierten Prozedur folgende Lösung gewählt werden:

  PROGRAM datum8;         { Turbo Pascal }
  USES Dos;

  TYPE weekdays = (monday, tuesday, wednesday, thursday, friday,
                   saturday, sonday);

       datew = OBJECT
                 day : 1..31;
                 month : 1..12;
                 year : 0..2000;
                 day_of_the_week : weekdays;
                 PROCEDURE init;
               END;

  PROCEDURE datew.init;
  VAR d, m, y, w : WORD;
  BEGIN
    GetDate(y, m, d, w);
    day := d;
    month := m;
    year := y;
    day_of_the_week := weekdays(w);
  END;

  VAR datum : datew;

  BEGIN
    datum.init;
    WITH datum DO
      Writeln(day, '.', month, '.', year);
  END.
datew ist jetzt ein "richtiger" Objektdatentyp, da mit init eine Methode definiert wurde.


Version 9

Die obige Version ist inkonsequent: Nicht alle Operationen über den Datumswerten sind objektorientiert angelegt, siehe die Ausgabe der Datumswerte.
Die nachfolgende Programmversion zeigt die Lösung dieses Problems und deutet mögliche Erweiterungen an:

  PROGRAM datum9;         { Turbo Pascal }
  USES Dos;

  TYPE weekdays = (monday, tuesday, wednesday, thursday, friday,
                   saturday, sonday);

       datew = OBJECT
                 day : 1..31;
                 month : 1..12;
                 year : 0..2000;
                 day_of_the_week : weekdays;
                 PROCEDURE init;
                 PROCEDURE list;
                 PROCEDURE next;
                 { weitere Methoden }
               END;

  PROCEDURE datew.init;
  VAR d, m, y, w : WORD;
  BEGIN
    GetDate(y, m, d, w);
    day := d;
    month := m;
    year := y;
    day_of_the_week := weekdays(w);
  END;

  PROCEDURE datew.list;
  TYPE wdays = ARRAY[weekdays] OF STRING[10];
  CONST wday : wdays = ('Sonntag', 'Montag', 'Dienstag', 'Mittwoch',
                        'Donnerstag', 'Freitag', 'Samstag');
  BEGIN
    Writeln(day, '.', month, '.', year, ', ', wday[day_of_the_week]);
  END;

  PROCEDURE datew.next;
  BEGIN
    { Ermittlung und Ausgabe des nachfolgenden Tages }
  END;

  VAR datum : datew;

  BEGIN
    datum.init;
    datum.list;
  END.


P. Böhme, 26.08.1995