\chapter{Die persistente Programmierumgebung Tycoon}
\label{tycoon}

Bevor die in der Einf"uhrung kurz skizzierten Dienste behandelt werden, soll
an dieser Stelle auf die f"ur diese Arbeit wesentlichen Aspekte des
Tycoon-Systems eingegangen werden. Zun"achst wird die
Architektur dieses Systems und die Einordnung der in dieser Arbeit 
entwickelten Dienste in diese Architektur dargestellt. 
Grundlage f"ur Kapitel~\ref{gdl} und
\ref{reflection} bilden au"serdem die im Anschlu"s erl"auterten statischen und 
dynamischen Aspekte des Typsystems von \TL\ sowie die Darstellung von 
Programmierstilen in \TL.

Nicht eingegangen werden soll dagegen auf Syntax und elementare Konzepte von
\TL. Zum Verst"andnis der in dieser Arbeit dargestellten 
Programmbeispiele sei auf die Einf"uhrung in \cite{MMS94} verwiesen. Details 
zur praktischen Benutzung der interaktiven Systemumgebung und der Bibliotheken 
finden sich in \cite{MMM93}.

	\section{Architektur des Tycoon-Systems}

Die Architektur des Tycoon-Systems beruht auf konsequenter Trennung
der Aufgaben Datenmodellierung, Datenmanipulation und
Datenspeicherung. Diese Trennung wird veranschaulicht in Abbildung
\ref{tycoon-arch}. 

\begin{figure}
\leavevmode
\def\epsfsize#1#2{0.8\textwidth}
\centerline{\epsffile{tycoon-arch.epsf}}
\caption{\label{tycoon-arch} Tycoon Systemarchitektur}
\end{figure}

In dieser Architektur lassen sich zwei grundlegende Anwendungsebenen 
identifizieren. Auf unterer Ebene ist das Tycoon-Laufzeitsystem Anwender
(Klient) der abstrakten, modell\-un\-abh"angigen Objektspeicherschnittstelle
\TSP\footnote{\TSP: {\em Tycoon Store Protocol}, Details zu Eigenschaften der 
Schnittstelle und zur Datenrepr"asentation siehe \cite{Matt93}}. 
Die h"ohere Anwendungsebene
stellt die \TL-Sprachebene dar, die durch den \TL-Compiler realisiert wird. 
Auf ihr setzen Anwendungsbibliotheken auf, welche sich in {\em interne} und 
{\em externe} Bibliotheken gliedern. Letztere sind Ausdruck der Offenheit des 
Systems gegen"uber externen Diensterbringern, welche durch den in 
Kapitel~\ref{gdl} beschriebenen generischen Gateway-Dienst noch erweitert wird.

Zwischen den beiden Anwendungsebenen liegt die Ebene \TML\footnote{\TML: 
{\em Tycoon Machine Language}}. \TML\ stellt eine baumstrukturierte, 
untypisierte, portable
Zwischenrepr"asentation dar und wird f"ur diverse quellsprachen- und
zielmaschinenunabh"angige statische (zur "Ubersetzungszeit) und dynamische (zur
Laufzeit) Optimierungen genutzt \cite{GaMa94}.

Alle oberhalb der \TVM\footnote{\TVM: {\em Tycoon Virtual Machine}}-Schicht 
liegenden Komponenten sind in \TL\ selbst implementiert. Dadurch wird der 
{\em bootstrap}
des Systems auf unterschiedlichen Hard- und Softwarearchitekturen unterst"utzt.
Durch die Implementierung gro"ser Teile des Systems in \TL\ und die 
Einf"uhrung dynamischer Typen ist es nun m"oglich, Teile des
Compilers, die bisher unterhalb der \TL-Ebene lagen wie die
Benutzerschnittstelle zum Compiler oder die Modulverwaltung, auf die obere 
Anwendungsebene zu verlagern, wie in Abbildung \ref{tycoon-arch-new}
dargestellt. 

\begin{figure}
\leavevmode
\def\epsfsize#1#2{0.8\textwidth}
\centerline{\epsffile{tycoon-arch-new.epsf}}
\caption{\label{tycoon-arch-new} Reflektive Tycoon Systemarchitektur}
\end{figure}

Durch diese "Offnung der Architektur soll insbesondere der Compiler 
dem Benutzer als Bibliotheksdienst zug"anglich gemacht werden. Werkzeuge der
Programmierumgebung treten dann nicht mehr als ins System integrierte,
sozusagen "`fest verdrahtete"' Komponenten auf, sondern als Benutzer dieses
Bibliotheksdienstes. Dadurch werden die notwendigen Voraussetzungen zur 
{\em reflektiven Programmierung} erf"ullt, welche Gegenstand von 
Kapitel~\ref{reflection} ist.


	\section{Erl"auterung ausgew"ahlter Typkonzepte von TL}
	\label{typkonzepte}

Grundlegend f"ur alle statischen Aussagen "uber die Semantik von
\TL-Ausdr"ucken ist der Begriff der {\em Signatur}. Eine Signatur ordnet einem
Namen statische Information in Form eines {\sl Typausdrucks} zu \cite{Matt93}.
Solche Typaussagen der Form $x :T$ stellen {\em partielle} Spezifikationen dar, 
d.h.  der an {\sl x} gebundene Wert erf"ullt mindestens die durch den Typ 
{\sl T} gegebene Spezifikation, m"oglicherweise jedoch auch eine pr"azisere.
Die partielle Ordnung auf Typen und Typoperatoren ("`ist pr"aziser als"') wird 
dabei durch die 
transitive und reflexive {\em Subtyp\-beziehung}\footnote{ausgedr"uckt durch das 
Infixsymbol $<:$} beschrieben, wobei das {\em Subsumptionsprinzip}
($a :A \wedge A <:B \Rightarrow a :B$) gilt. Zur Definition von
Subtyp\-beziehungen f"ur die einzelnen Typkonstruktoren ist noch der Begriff der
{\em Subsignatur} wichtig. Signaturen $S$ ($x_{1}
:T_{1}, x_{2} :T_{2}, \dots x_{n} :T_{n}$) hei"sen Subsignaturen
%\footnote{
%ausgedr"uckt durch das Infixsymbol $<::$} 
von $S'$, 
wenn die Anzahl der Signaturkomponenten in $S$ gleich derjenigen in $S'$ ist und 
$T_{i} <: T'_{i}$ sowie $x_{i} = x'_{i}$ f"ur alle $i \in \{1..n\}$ 
gilt, wobei $x_{i}$ und $x'_{i}$ beide nicht anonym sein d"urfen.

Der Typ {\bf Ok} (triviale Typspezifikation) ist Supertyp aller 
nichtparametrisierten Typen\footnote{d.h. nicht von Typoperatoren}, w"ahrend
der Typ {\bf Nok} (Ergebnistyp aller Ausdr"ucke, die eine Ausnahme ausl"osen) 
Sub\-typ aller nichtparametrisierten Typen ist. Die
Basistypen stehen zueinander nicht in einer Sub\-typ\-be\-ziehung. (Abbildung
\ref{typhierarchie} links). Parametrisierte Typen (Typoperatoren) erster Stufe
lassen sich anhand der Zahl ihrer Argumente in eine Typhierarchie einordnen. 
In Abbildung
\ref{typhierarchie} sind die Hierarchien f"ur Typoperatoren mit einem bzw. zwei 
Argumenten dargestellt, jeweils mit ihren h"ochst- und niedrigstliegenden
Vertretern und jeweils zwei Beispielen benutzerdefinierter Typoperatoren. 
Sub\-typisierung von Typoperatoren erfolgt gem"a"s der Kontravarianzregel. 
Typ\-operatoren
h"oherer Stufe, d.h. Typoperatoren, die Typoperatoren als Argument akzeptieren
oder einen Typoperator generieren, bilden wiederum separate Typhierarchien.

\begin{figure}
\leavevmode
\def\epsfsize#1#2{0.8\textwidth}
\centerline{\epsffile{typhierarchie.epsf}}
\caption{\label{typhierarchie} \TL-Typhierarchien}
\end{figure}

	\subsection{Struktur- und Namens"aquivalenz}

Subtypisierung beruht in \TL\ auf {\em struktureller} Kompatibilit"at. Dies
dr"uckt sich in den Subtypsierungsregeln f"ur Tupel-, Record- und
Funktionstypen aus.
\begin{description}
\item [Tupel ohne Varianten:] Seien A und B Tupeltypen ohne Varianten, 
dann gilt A $<:$ B, wenn A ein Pr"afix von Signaturen besitzt, die
Subsignaturen von B sind.
\item [Records:] Seien A und B Recordtypen, dann gilt A $<:$ B, wenn die
Signaturen von A eine Teilmenge der Signaturen von B enthalten, deren Elemente
Subsignaturen der Signaturen von B sind.
\item [Funktionen:] Es gilt die Kontravarianzregel.
\end{description}
F"ur weitere Subtypisierungsregeln sei auf den Sprachreport \cite{MaSc92}
verwiesen.
Eine Ausnahme von der Struktur"aquivalenz bildet die Kompatibilit"atsregel 
f"ur {\em abstrakte} Typvariablen, die auf Namens"aquivalenz beruht.
Beispiele zur Definition abstrakter Datentypen finden sich in 
Abschnitt~\ref{programmierstile}. An dieser Stelle soll das Zusammenspiel 
von Struktur- und Namens"aquivalenz beispielhaft erl"autert werden.

Um zuf"allige, d.h. nicht gew"unschte Kompatibilit"aten zwischen strukturell
"aquivalenten Typen zu vermeiden, l"a"st sich die M"oglichkeit, in \TL\ {\em
einschr"ankende} Wert- und Typbindungen zu definieren, zusammen mit der
Namens"aquivalenzregel f"ur abstrakte Typvariablen zum Konzept der
{\em semi-abstrakten} Typvariablen kombinieren. Das folgende Beispiel 
veranschaulicht die Vorteile dieser Kombination aus Struktur- und 
Namens"aquivalenz:

\begin{xple}
  \kw{Let} Person = \kw{Tuple} name :String  age :Int \kw{end}
  \kw{let} person :\kw{Tuple} T $<:$Person  new(:Person) :T \kw{end} = 
    \kw{tuple} \kw{Let} T = Person  \kw{let} new(x :Person) = x \kw{end}

  \kw{Let} Building = \kw{Tuple} name :String  age :Int \kw{end}
  \kw{let} person :\kw{Tuple} T $<:$Building  new(:Building) :T \kw{end} = 
    \kw{tuple} \kw{Let} T = Building  \kw{let} new(x :Building) = x \kw{end}

  \kw{let} married(p1, p2 :person.T) :Bool = string.equal(p1.name p2.name)
  \kw{let} eiffelTower = building.new(\kw{tuple} ''Tour d\' Eiffel'' 95 \kw{end})
  \kw{let} meyer = person.new(\kw{tuple} ''Meyer'' 50 \kw{end})

  married(eiffelTower meyer)
  $\Rightarrow$ Argument type mismatch: 'person.T' expected, 'building.T' found
      [while checking function argument 'p1']
\end{xple}

Die Typvariablen {\sl person.T} bzw. {\sl building.T} hei"sen semi-abstrakt,
da sie nicht nur die triviale Spezifikation ($<:${\bf Ok}) erf"ullen, sondern
jeweils auch eine speziellere. Der im Beispiel versuchte Aufruf der Funktion
{\sl married} l"a"st sich nicht korrekt "ubersetzen, da das erste Argument
aufgrund der Namens"aquivalenzregel f"ur abstrakte Typvariablen nicht die 
Bedingung $<:${\sl person.T} erf"ullt, obgleich die Typstruktur des Wertes
{\sl eiffelTower} "aquivalent zur Struktur von Werten des Typs {\sl Person}
ist. Allerdings lassen sich auf Werte eines semi-abstrakten Typs alle Operationen
anwenden, die auf Werte des als obere Schranke hinter dem $<:$-Zeichen 
angegebenen Typs definiert sind. W"urde man bei den Bindungen der Bezeichner 
{\sl person} bzw. {\sl building} den einschr"ankenden Typ weglassen, so
h"atten diese Bindungen den vom Compiler inferierten Typ. Die
jeweilige Typvariable {\sl T} w"are dann nicht abstrakt, so da"s der Aufruf von
{\sl married} wegen der Struktur"aquivalenz von {\sl Person} und {\sl Building}
fehlerfrei "ubersetzt werden w"urde.


	\subsection{Dynamische Typisierung}
	\label{oldDynTypes}

In datenintensiven, langlebigen und/oder verteilten Anwendungen kann der
Programmierer mit Situationen konfrontiert werden, in denen notwendige
Typ"uberpr"ufungen erst zur Laufzeit m"oglich sind (n"aheres dazu in 
Abschnitt~\ref{dynamicTypes}). Zur Behandlung dieser Situationen werden in 
\cite{MaSc92} zwei Sprachkonstrukte vorgeschlagen:
\begin{enumerate} 
\item Signaturen von Typvariablen k"onnen mit dem Schl"usselwort {\bf Dyn}
versehen werden.
\item Diese so annotierten Typvariablen k"onnen durch einen {\bf
typecase}-Ausdruck ("ahnlich dem {\bf case}-Konstrukt) zur Laufzeit inspeziert 
werden. 
\end{enumerate} 
In jedem Zweig des {\bf typecase}-Ausdrucks wird die dynamische Typvariable auf 
einen statisch bekannten Typ eingeschr"ankt, wodurch der Zugriff auf 
Werte dieses dynamischen Typs statisch "uberpr"uft werden kann. Es wird
derjenige {\bf when}-Zweig gew"ahlt, dessen Typ zuerst Subtyp des dynamischen 
Typs ist. Trifft dies auf keinen {\bf when}-Zweig zu, wird der {\bf
else}-Zweig ausgef"uhrt. Mit diesen
Konstrukten lassen sich ad hoc-polymorphe Funktionen wie im folgenden Beispiel
formulieren:
\begin{xple}
 \kw{let} inspect(\kw{Dyn} T $<:$\kw{Ok})  = 
   \kw{typecase} T
   \kw{when} Int \kw{then} \dots
   \kw{when} String \kw{then} \dots
   \kw{when Tuple} name :String \kw{end then} \dots
   \dots
   \kw{else} \dots
   \kw{end}
\end{xple}
Dieser Ansatz wurde jedoch in der Tycoon-Implementierung nicht
weiterverfolgt, da das {\bf typecase}-Konstrukt nur eine Projektion eines 
dynamischen Typs auf einen
festen statischen Typ erlaubt. Da jeder m"ogliche Zweig statisch
antizipiert werden mu"s, ist es nicht m"oglich, {\em typ\-ge\-steu\-erte},
algorithmisch vollst"andige Berechnungen durchzuf"uhren.
Insbesondere die oben skizzierte Funktion {\sl inspect} zur Abfrage der
Struktur eines dynamischen Typs ist mit diesen Konzepten nicht
implementierbar, da die Menge m"oglicher {\bf when}-Zweige des {\bf
typecase}-Ausdrucks unendlich ist.
Weiterhin kann sie nicht auf
Typoperatoren verallgemeinert werden, da diese separate Typhierarchien bilden,
wie schon in Abbildung \ref{typhierarchie} dargestellt. Es w"are dann
pro Hierarchie genau eine Funktion zu implementieren, wobei die Zahl m"oglicher
Hierarchien wiederum unendlich ist. In Abschnitt~\ref{dynamicTypes} wird 
daher ein alternativer Ansatz vorgestellt und implementiert, der die genannten
Einschr"ankungen "uberwindet.


		\section{Programmierstile in Tycoon}
		\label{programmierstile}

Die Idee einer interaktiven, grafischen Programmierwerkbank taucht "uberwiegend
im Zusammenhang mit objektorientierten Systemen auf (z.B. \cite{GoRo89}).
Dies legt die Vermutung nahe, da"s objektorientierte Konzepte
als Hilfsmittel zur Verwirklichung dieser Idee besonders geeignet sind. Eine
Sprache, die solche Konzepte unterst"utzt, w"are dann in einem noch h"oheren
Ma"se im Vorteil gegen"uber Sprachen, die diese nicht unterst"utzen, denn 
neben den 
software-technischen Vorteilen (Wiederverwendbarkeit von Code, Klassifizierung,
h"oherer Abstraktionsgrad) kommt dann noch die bessere Unterst"utzung durch 
Werkzeuge hinzu. Diese ist durch die zunehmende Komplexit"at von 
Software-Systemen unverzichtbar geworden.

Gute Werkzeugunterst"utzung innerhalb einer Programmierumgebung h"angt aber auch
stark von der M"oglichkeit der Integration einer gro"sen Klasse externer 
Diensterbringer ab. Die sprachliche Ausgestaltung von \TL\ wurde deshalb 
m"oglichst datenmodellneutral
gew"ahlt. So werden nicht nur funktionale und imperative, 
sondern auch objektorientierte Modellierungsans"atze unterst"utzt. 
Objektorientierte Modellierungsmittel unterst"utzen somit auch indirekt den
Werkbankgedanken wie in Abbildung \ref{argumentation} verdeutlicht. 
% AG: Bezug? (somit)

\begin{figure}[h]
\leavevmode
\def\epsfsize#1#2{0.6\textwidth}
\centerline{\epsfbox{OO-Argumentation.epsf}}
\caption{\label{argumentation} Determinanten der Werkzeugunterst"utzung}
\end{figure}

Nachfolgend wird diskutiert, inwiefern sich bestimmte sprachliche
Abstraktionen von \TL\ zur Repr"asentation objektorientierter Konzepte eignen.
Diese Diskussion bildet die Grundlage f"ur die in 
Abschnitt~\ref{sprachabbildung} gew"ahlte Abbildung von C++ nach \TL. 
Es werden Vor- und Nachteile des modularen gegen"uber dem
objektorientierten Programmierstil behandelt und gezeigt, da"s der in \TL\
realisierbare objektorientierte Programmierstil zwar neben rein notationellen 
auch weitere Modellierungsvorteile bietet, da"s diese aber durch einen erheblich
h"oheren Ressourcenbedarf erkauft werden. Um diesen Bedarf zu verringern ist
weitergehende Systemunterst"utzung notwendig, z.B. durch syntaktische 
Erweiterung verbunden mit einer "Anderung der statischen Semantik von \TL\ oder
durch die Implementierung eines objektorientierten Typsystems, wie sie
z.Zt. mit der Entwicklung der auf \TML\ aufsetzenden Sprache 
TooL\footnote{TooL: Tycoon object oriented Language} \cite{GaMa95a} verfolgt 
wird.

Die Hauptkonzepte objektorientierter Programmierung sind Datenkapselung,
dynamische Bindung, Subtyppolymorphismus und Vererbung. Nachfolgend wird
die Umsetzung dieser Konzepte im modularen (soweit m"oglich) bzw. im 
objektorientierten Stil diskutiert.

	\subsection{Datenkapselung}
	\label{datenkapselung}

Der heutzutage sehr hohe Anteil an symbolischer und datenintensiver
Verarbeitung in datenverarbeitenden Systemen legt eine {\em datenorientierte} 
Modellierung nahe. Sowohl die modulare als auch die objektorientierte
Programmierung beinhalten das Konzept des abstrakten Datentyps (ADT). 
In Tycoon k"onnen Modulschnittstellen zur Definition eines ADT verwendet
werden. Diese werden durch Tupel- oder Recordtypen repr"asentiert:
\begin{xple}
  \kw{Let} Preview = \kw{Tuple}
     T $<:$\kw{Ok}
     new() :T
     changeCurrentPage(self :T currentPage :Int) :\kw{Ok}
     getCurrentPage(self :T) :Int
     changeZoomFactor(self :T factor :Real) :Real
     \dots
  \kw{end}

\end{xple}
Der Tupelttyp {\sl Preview} wird dabei als abstrakter Datentyp und die 
Typvariable {\sl T} in der Signatur von {\sl Preview} als abstrakte Typvariable 
bezeichnet. 

Die Modulimplementation ist dann ein Wert dieses Schnittstellentyps, 
der entsprechende Wertbindungen f"ur die ADT-Funktionen, die
Objektgenerierungsfunktion und eine Typbindung f"ur die abstrakte Typvariable
aggregiert.
\begin{xple}
  \kw{let} preview = \kw{tuple}
     \kw{Let} T = Word
     \kw{let} new() :T = \dots
     \dots
  \kw{end}
\end{xple}
Der Tupelwert {\sl preview} wird als Implementierung des abstrakten Datentyps 
und der Typ {\sl Word} als Repr"asentationstyp bezeichnet.
Die abstrakte Typvariable {\sl T} ist inkompatibel zu ihrem
Repr"asentationstyp. Im obigen Beispiel bedeutet dies, da"s ein Wert vom Typ
{\sl preview.T} nicht an Positionen verwendet werden darf, die einen Wert vom Typ
{\sl Word} fordern.
Da verschiedene Tupelwerte des abstrakten Datentyps konstruierbar sind,
k"onnen mehrere Modulimplementationen eines Schnittstellentyps koexistieren. 

Der "Ubergang zur objektorientierten Methodik geschieht nun dadurch, da"s in 
der Signatur des Objekttyps die abstrakte Typvariable sowie die
Objektgenerierungsfunktion(en) eliminiert werden. Der implizit gekapselte
Objektzustand macht au"serdem die "Ubergabe eines Wertes des abstrakten Typs
an die Funktionen des ADT "uberfl"ussig \cite{Matt93}. Dies f"uhrt in diesem 
Beispiel zu folgendem Objekttyp:
\begin{xple}
  \kw{Let} PreviewOO = \kw{Tuple}
     changeCurrentPage(currentPage :Int) :\kw{Ok}
     getCurrentPage() :Int
     changeZoomFactor(factor :Real) :Real
     \dots
  \kw{end}
\end{xple}

Die Objektgenerierungsfunktion liefert nun einen Wert dieses Objekttyps, wobei
der Objektzustand im statischen Abschlu"s ({\em static closure}) aller
ADT-Funktionen enthalten ist. 
\begin{xple}
  \kw{let} newPreviewOO() :PreviewOO = \kw{begin}
     \kw{let} state = \dots (* nicht exportierte Bindung *)
     \kw{tuple}
       \kw{let} changeCurrentPage(currentPage :Int) :\kw{Ok} = \dots
           \dots (* weitere exportierte Methoden *)
     \kw{end}
  \kw{end}
\end{xple}

Die Vorteilhaftigkeit dieser Modellierung wird am folgenden Beispiel deutlich:
\begin{xple}
  (* Modulimplementierungen *)
  \kw{let} preview1 :Preview = \kw{tuple} \kw{Let} T = \dots \kw{end}
  \kw{let} preview2 :Preview = \kw{tuple} \kw{Let} T = \dots \kw{end}

  (* Instanzen der ADTs *)
  \kw{let} p1 = preview1.new()
  \kw{let} p2 = preview2.new()

  (* Objektgenerierungsfunktionen *)
  \kw{let} newPreview1() :PreviewOO = \dots
  \kw{let} newPreview2() :PreviewOO = \dots

  (* Objekttyp-Instanzen *)
  \kw{let} p3 = newPreview1()
  \kw{let} p4 = newPreview2()
\end{xple}
In \TL\ gilt, da"s verschiedene Implementierungen abstrakter
Datentypen untereinander nicht kompatibel sind, es gilt also
Namens"aquivalenz.
In diesem Beispiel sind die Typen von p1 und p2 nicht kompatibel, 
da weder ihre Namen "aquivalent sind (preview1.T $\not\equiv$ preview2.T),
noch eine Subtypbeziehung zwischen ihnen besteht. 
P3 und p4 hingegen sind vom gleichen Typ (PreviewOO), obwohl sie 
unterschiedlich implementiert wurden. 

Das Speichern der Methodenzeiger beim Objekt stellt sicher, da"s
die zum Objekt\-zustand passende Methode gew"ahlt wird (dynamische Bindung) und 
bietet au"serdem
einen notationellen Vorteil beim Methodenaufruf ({\sl objekt.methode()} 
statt {\sl modul.methode(exemplarvariable)}). 

Diese beiden Vorteile werden jedoch gegen einen
erheblich gr"o"seren Speicherplatzbedarf f"ur Objekte eingetauscht, denn 
die Methoden werden {\em pro Instanz eines Objekttyps} gespeichert. 
Insbesondere bei der Modellierung von komplexen Vererbungssituationen 
wird dieser Umstand untragbar (siehe n"achster Abschnitt).

	\subsection{Vererbung und Subtyppolymorphismus}

Vererbung unterst"utzt die inkrementelle Software-Entwicklung.
In einigen objektorientierten Sprachen (z.B. C++, Eiffel) dient das 
entsprechende
Sprachkonzept nicht nur zur Wiederverwendung von Code, sondern f"uhrt auch zu 
einer expliziten Subtypisierung und damit zum Subtyppolymorphismus. 
In \TL\ hingegen werden Subtypbeziehungen durch den Typ"uberpr"ufer inferiert
und nicht explizit durch den Programmierer festgelegt.
Sprachkonstrukte zur Modellierung von Vererbungssituationen existieren 
{\em unabh"angig} von Subtypisierung und Subtyppolymorphismus und bedingen 
diese nicht. 

Angenommen, der Objekttyp PreviewOO im vorigen Beispiel soll Methoden des
Objekttyps Window {\em und} Printer "`erben"', so l"a"st sich dies in \TL\
mit Hilfe der {\em Repeat}-Anweisung realisieren:
\begin{xple}
\kw{Let} WindowOO = \kw{Tuple}
   show() :\kw{Ok}
   \dots
\kw{end}

\kw{Let} PreviewOO = \kw{Tuple}
   \kw{Repeat} WindowOO
   changeCurrentPage(currentPage :Int) :\kw{Ok}
   getCurrentPage() :Int
   changeZoomFactor(factor :Real) :Real
   \dots
\kw{end}
\end{xple}
Hierdurch werden im Objekttyp {\sl PreviewOO} alle Signaturen (d.h. die 
exportierten Methoden) des Objekttyps {\sl WindowOO} wiederholt und die 
gew"unschte Subtypbeziehung ({\sl PreviewOO} $<:$ {\sl WindowOO}) ist erreicht. 
In der Objektgenerierungsfunktion werden 
durch die {\bf open}-Anweisung den Signaturen der Methoden entsprechende 
Wertbindungen wiederholt:
\begin{xple}
\kw{let} newWindowOO = \kw{begin}
   \kw{let} show() :\kw{Ok} = \dots
   \dots
\kw{end}

\kw{let} newPreviewOO = \kw{begin}
   \kw{let} window = newWindowOO()
   \kw{tuple} 
      \kw{open} window
      \kw{let} changeCurrentPage(currentPage :Int) :\kw{Ok} = \dots
      \dots
   \kw{end} 
\kw{end}
\end{xple}
Im modularen Stil l"a"st sich Subtyppolymorphismus im Beispiel wie folgt
erreichen:
\begin{xple}
\kw{Let} Preview = \kw{Tuple}
   T $<:$window.T     (* Export einer einschr"ankenden Typbindung *)
   new() :T
   \dots
\kw{end}
\end{xple}
Die {\em Repeat}-Anweisung l"a"st sich auch in der Modulschnittstelle
verwenden:
\begin{xple}
\kw{Let} Preview = \kw{Tuple}
   \kw{Repeat} Window
   T $<:$window.T     
   new() :T
   \dots
\kw{end}
\end{xple}
Will man jetzt f"ur einen Wert vom Typ {\sl preview.T} eine ADT-Funktion eines 
Supertyps aufrufen, so braucht man nicht mehr zu wissen, welches Modul
die Signatur dieser Funktion exportiert, da sie durch die 
{\em Repeat}-Anweisung auch in der Modulschnittstelle {\sl Preview} sichtbar ist. 
Will man allerdings als menschlicher Leser vom angewandten Auftreten einer
Funktion zu ihrer  Definitionsstelle gelangen, mu"s man u.U. die ganze 
ADT-Hierarchie durchsuchen, um ihre Signatur zu erfahren. Dies ist auch ein
h"aufig genannter Kritikpunkt am objektorientierten
Programmierstil. Dieser Nachteil wird h"aufig durch Werkzeugeinsatz 
(z.B. Klassen-Browser) zu kompensieren versucht.

Zur Modellierung von Mehrfachvererbung ist der Record-Typkonstruktor
geeignet, da aufgrund der Subtypisierungsregel f"ur Recordtypen eine aus
Recordtypen bestehende Subtyp\-hierarchie einen gerichteten azyklischen Graphen
(und nicht nur eine Baumstruktur) bilden kann. 
\begin{xple}
  \kw{Let} PreviewOO = \kw{Record}
    \kw{Repeat} WindowOO
    \kw{Repeat} PrinterOO
    \dots
  \kw{end}
\end{xple}
Falls {\sl WindowOO} und {\sl PrinterOO} Recordtypen sind, gilt:

\begin{math}
\label{mi-bsp}
(PreviewOO <:WindowOO) \wedge (PreviewOO <:PrinterOO)
\end{math}

Im modularen Stil l"a"st sich ein solcher Sachverhalt nicht ausdr"ucken, da
f"ur abstrakte Typvariablen h"ochstens {\em ein} einschr"ankender Typ
angegeben werden kann (z.B. $T <:window.T$, nicht aber 
$T <:window.T, printer.T$).

