next up previous
Nächste Seite: Typentests Aufwärts: OO-Techniken in Oberon Vorherige Seite: Das Modulkonzept von Oberon


Typerweiterungen

Recordtypen können als Erweiterung eines anderen Recordtyps definiert werden. Im Beispiel sind Rectangle und Circle Erweiterungen von Figure:

TYPE
   Figure =
      RECORD
         x, y: INTEGER; (* center *)
      END;
   Rectangle =
      RECORD
         (Figure)
         w, h: INTEGER;
      END;
   Circle =
      RECORD
         (Figure)
         r: INTEGER;
      END;

Eine Erweiterung übernimmt dabei sämtliche Komponenten der übergeordneten Typen. Abbildung 2.1

Abbildung: Einfache Typenhierarchie mit den zugehörigen Komponenten
\begin{figure}\epsfig{file=figure-hier.eps}\end{figure}

zeigt dies für das obige Beispiel.

Das Wesentliche daran ist die Kompatibilität zwischen dem Basistyp (im Beispiel Figure) und den abgeleiteten Typen. So ist die Zuweisung eines Rectangle an eine Figure zulässig. Da der Basistyp jedoch nur einen Teil umfaßt, findet dabei implizit eine Projektion statt. Andererseits die Zuweisung eines Basistyps an eine Erweiterung nicht zugelassen, da dann Komponenten undefiniert bleiben würden:

VAR
   figure: Figure;
   rectangle: Rectangle;
   circle: Circle;

(* ... *)

figure := rectangle; (* zulaessig: nur die Komponenten x und y werden zugewiesen *)
rectangle := figure; (* nicht zulaessig *)
rectangle := circle; (* nicht zulaessig *)

Eine Projektion findet jedoch nicht statt, wenn ein Record als VAR-Parameter übergeben wird:

PROCEDURE Move(VAR figure: Figure; newx, newy: INTEGER);
BEGIN
   figure.x := newx;
   figure.y := newy;
END Move;

(* ... *)

Move(circle, 0, 0); (* ist legal *)

Die Kompatibilitätsregeln erstrecken sich auch auf entsprechende Zeigertypen:

TYPE
   FigurePtr = POINTER TO Figure;
   RectanglePtr = POINTER TO Rectangle;
   CirclePtr = POINTER TO Circle;
VAR
   figurePtr: FigurePtr;
   rectanglePtr: RectanglePtr;
   circlePtr: CirclePtr;

(* ... *)

figurePtr := rectanglePtr; (* zulaessig, jedoch keine Projektion *)
rectanglePtr := figurePtr; (* nicht zulaessig *)
rectanglePtr := circlePtr; (* nicht zulaessig *)

Entsprechend lassen sich folgende Definitionen geben: Gegeben sei eine Deklaration der Form

T0 = RECORD (T) ... END;

Dann ist T0 eine (direkte) Erweiterung von T und T ist der (direkte) Basistyp von T0.

Erweiterte Typen können erneut erweitert werden: Ein Recordtyp U ist eine Erweiterung des Recordtyps T genau dann, falls

Entsprechend ist ein Recordtyp T genau dann ein Basistyp eines Recordtyps U, wenn U eine Erweiterung von T ist.

Diese Definitionen erstrecken sich auf die zugehörigen Zeigertypen. Seien folgende Definitionen gegeben:

TYPE P = POINTER TO T;
TYPE Q = POINTER TO U;

Dann ist ein Zeigertyp Q genau dann eine Erweiterung eines Zeigertyps P, wenn U eine Erweiterung von T ist. Ein Zeigertyp P ist genau dann ein Basistyp eines Zeigertyps Q, wenn Q eine Erweiterung von P ist.

Kompatibilitätsregeln sind bei Records und Zeigern an zwei Stellen von Interesse: bei der Zuweisung und der Parameterübergabe. Bei Parameterübergaben gibt es Werteparameter, die analog zu Zuweisungen behandelt werden, und Variablenparameter. Generell gilt, daß eine Zuweisung oder Parameterübergabe dann zulässig ist, wenn der Typ des zuzuweisenden oder zu übergebenden Objekts eine Erweiterung des Typs des Zielobjekts bzw. des formalen Parameters ist. Hierzu gibt es einige Ausnahmen, die in diesem Zusammenhang jedoch nicht von Bedeutung sind.

Im Normalfall lassen sich alle Kompatibilitätsregeln statisch überprüfen. Eine Ausnahme ist bei Variablenparametern gegeben, wie folgendes Beispiel zeigt:

PROCEDURE Copy(VAR source, dest: Figure);
BEGIN
   dest := source;
END Copy;

(* ... *)

Copy(circle, rectangle);

Die Prozedur Copy ist, für sich gesehen, statisch vollkommen in Ordnung, da der formale Parametertyp von source und dest identisch ist. Andererseits ist der Aufruf ebenfalls korrekt, da sowohl Circle als auch Rectangle Erweiterungen von Figure sind. Zur Laufzeit stellt sich dann jedoch heraus, daß versucht wird, einer Variablen vom Typ Circle einen Wert vom Typ Rectangle zuzuweisen.

Dies passiert jedoch nur bei Zuweisungen von Variablenparametern. Wie bereits erwähnt, ist die Zuweisung von Records mit unbekannten Teilen problematisch. Hier ist zwar möglicherweise Figure in vollem Umfang bekannt, jedoch nicht die potentiellen Erweiterungen. Ein generelles Verbot solcher Zuweisungen würde jedoch zu weit gehen, da dann auch ``ganz normale'' Records im Rahmen konventionellen Programmierstils davon bedroht wären, die normalerweise nicht erweitert werden.

Das gleiche Problem ergibt sich auch bei Zuweisungen von Variablenparametern, die einen Zeigertyp haben. Der Ulmer Oberon-Übersetzer generiert für alle diese Fälle Laufzeitüberprüfungen und bestimmt bei Records die korrekte Projektion zur Laufzeit.


next up previous
Nächste Seite: Typentests Aufwärts: OO-Techniken in Oberon Vorherige Seite: Das Modulkonzept von Oberon
Andreas Borchert 2000-12-18