#LyX 2.0 created this file. For more info see http://www.lyx.org/ \lyxformat 413 \begin_document \begin_header \textclass article \begin_preamble \usepackage{multicol} \end_preamble \use_default_options true \maintain_unincluded_children false \language ngerman \language_package default \inputencoding utf8 \fontencoding global \font_roman default \font_sans default \font_typewriter default \font_default_family default \use_non_tex_fonts false \font_sc false \font_osf false \font_sf_scale 100 \font_tt_scale 100 \graphics default \default_output_format default \output_sync 0 \bibtex_command default \index_command default \paperfontsize default \spacing single \use_hyperref false \papersize default \use_geometry false \use_amsmath 1 \use_esint 1 \use_mhchem 1 \use_mathdots 1 \cite_engine basic \use_bibtopic false \use_indices false \paperorientation portrait \suppress_date false \use_refstyle 1 \index Index \shortcut idx \color #008000 \end_index \secnumdepth 3 \tocdepth 3 \paragraph_separation indent \paragraph_indentation default \quotes_language german \papercolumns 1 \papersides 1 \paperpagestyle default \tracking_changes false \output_changes false \html_math_output 0 \html_css_as_file 0 \html_be_strict false \end_header \begin_body \begin_layout Title Design Pattern und objekt--orientierte Programmierung \end_layout \begin_layout Author Bernd Paysan \end_layout \begin_layout Abstract \noun on Stephen Pelc \noun default hat auf der EuroForth ein dickes Fass aufgemacht, und aufgerufen: \begin_inset Quotes gld \end_inset Standardize OOP now! \begin_inset Quotes grd \end_inset In der darauf folgenden Diskussion hat sich gezeigt, dass jeder etwas anderes unter OOP versteht, und sich deshalb keine gemeinsame Praxis herauskristallisie ren kann. Dieser Artikel unternimmt den Versuch, da etwas Licht ins Dunkel zu bringen. OOP ist \begin_inset Quotes gld \end_inset no silver bullet, \begin_inset Quotes grd \end_inset wie \noun on Fred Brooks \noun default schreibt, es löst nicht das Problem, dass Programmieren schwer ist. Es ist aber ein brauchbares Werkzeug für eine Reihe von Problemen, die man anders noch schwerer lösen kann. \end_layout \begin_layout Standard \begin_inset ERT status open \begin_layout Plain Layout \backslash begin{multicols}{2} \end_layout \end_inset \end_layout \begin_layout Section* Einleitung \end_layout \begin_layout Standard Die \noun on Sapir--Whorf \noun default --Hypothese besagt, dass man nicht denken kann, was in der eigenen Sprache nicht ausgedrückt werden kann. Die Hypothese wurde ursprünglich bezüglich natürlicher Sprachen aufgestellt, und ist im Kern ein Konstrukt aus einer Zeit, in der andere Leute kulturelle Unterschiede mit Rassismus erklärt haben \begin_inset Foot status open \begin_layout Plain Layout Das heißt, die beiden Herren wollten damit erklären, \begin_inset Quotes gld \end_inset warum Neger doof sind, \begin_inset Quotes grd \end_inset statt erst mal herauszufinden, ob das überhaupt so ist, oder vielleicht gar nicht erklärt werden muss\SpecialChar \ldots{} \end_layout \end_inset . Sie gilt heute als widerlegt --- in jeder natürlichen Sprache kann man alles ausdrücken, es ist nur manchmal umständlicher als in anderen Sprachen. Und vor allem ist es schwieriger, sich in einer Sprache auszudrücken, die man nur mäßig beherrscht --- das ist dann auch der Grund, warum die beiden Herren zu ihrer Hypothese gekommen sind. \end_layout \begin_layout Standard Für Programmiersprachen gilt diese Kritik aber nicht --- Programmiersprachen sind künstlich, sie eröffnen tatsächlich einen Horizont zu einer neuen Denkweise, nämlich wie man einen Computer programmieren kann. Das ist etwas grundsätzlich anderes als sich mit Menschen zu unterhalten, weshalb Computersprachen auch grundsätzlich anders strukturiert sind als natürliche Sprachen. Die Denkweisen, die man mit einer Computersprache erlernt, sind neu, und eröffnen deshalb tatsächlich neue Horizonte. Die Konzepte, wie man sich in einer Computersprache ausdrückt, um gewisse Probleme elegant zu lösen, nennt man \begin_inset Quotes gld \end_inset Design Pattern. \begin_inset Quotes grd \end_inset Das war so Mitte der 90er--Jahre der Hype schlechthin, und ich habe mir damals natürlich das Buch der \begin_inset Quotes gld \end_inset Gang of Four \begin_inset Quotes grd \end_inset \begin_inset CommandInset citation LatexCommand cite key "gof" \end_inset aus der Uni--Bibliothek ausgeliehen und gelesen. Ich habe auch das Buch von \noun on Christopher Alexander \noun default \begin_inset CommandInset citation LatexCommand cite key "ca" \end_inset gelesen, ein Architekt, der das Konzept der Design Pattern im Zusammenhang mit Architektur entdeckt und beschrieben hat (schon in den 70ern), und dessen Buch Wegbereiter für diese Welle war --- und der sehr überrascht war, dass plötzlich eine Menge Informatiker sein Buch gelesen haben. Design Pattern werden durch die Möglichkeit einer Sprache vorgegeben --- das Design--Pattern--Buch, wenn man es so nennen will, für die natürlichen Möglichkeiten, die Forth von sich aus mitbringt, ist \begin_inset Quotes gld \end_inset Thinking Forth \begin_inset Quotes grd \end_inset von \noun on Leo Brodie \noun default \begin_inset CommandInset citation LatexCommand cite key "tf" \end_inset . \end_layout \begin_layout Standard Forth ist eine sehr flexible und dynamische Sprache, man kann es in alle möglichen Richtungen erweitern. Fügt man OOP zu Forth hinzu, so fügt man ein anderes Programmier--Paradigma hinzu, denn Forth selbst hat keine OOP--Fähigkeiten. Ich habe früher öfter gehört \begin_inset Quotes gld \end_inset Forth braucht kein OOP, wir haben ja CREATE DOES> \begin_inset Quotes grd \end_inset . Das ist so etwa, wie wenn man sagt \begin_inset Quotes gld \end_inset ich brauche keine Freundin, ich habe ja ein Fahrrad. \begin_inset Quotes grd \end_inset Man kann mit CREATE DOES> ein OOP--System implementieren, aber es selbst \emph on ist \emph default kein OOP. Genauso kann man mit dem Fahrrad zu seiner Freundin fahren, aber es \emph on ist \emph default keine Freundin. Die Philosophen bezeichnen so eine Antwort als \begin_inset Quotes gld \end_inset Kategoriefehler. \begin_inset Quotes grd \end_inset Es ist aber eine ganz normale Tatsache, dass man Dinge, die man nicht kennt, auch nicht vermisst. Insofern ist es nicht verwunderlich, dass der typische Forth--Programmierer mit CREATE DOES> und Fahrrad zufrieden ist ;-). CREATE DOES> ist eher so etwas wie eine Closure, also das Bündeln von Daten mit einer einzigen Funktion. \end_layout \begin_layout Standard OOP verspricht, komplexe Programme wartbar zu machen. Was wir durch OOP bekommen haben, sind riesige, schwerfällige Programme, die die Gigahertz--CPUs des 21. Jahrhunderts zum Schwitzen bringen, und die Terabyte--Festplatten füllen. Das ist aber kein Widerspruch, denn Programmierer neigen dazu, ihre Programme wachsen zu lassen, bis sie die Grenzen der Wartbarkeit erreicht haben. Im Umkehrschluss heißt das natürlich, dass Forth--Programme nur deshalb so kompakt und schnell sind, weil größere Programme in Forth einfach nicht mehr wartbar sind, und die Programmierer von sich aus darauf verzichten, sie mit Features zu überfrachten. Forth--Programmierer haben natürlich einen Ausweg aus dem Dilemma gefunden: es ist die Unzahl verschiedener, untereinander nicht kompatiblen OOP--Erweiteru ngen, die auch OOP--basierte Forth--Programme ab einer gewissen Größe unwartbar machen (zumindest für dritte, denn ab einer gewissen Größe braucht man Teams von Programmierern, um Programme weiter wachsen zu lassen), also dafür sorgen, dass sie klein und schnell bleiben. \end_layout \begin_layout Standard \noun on Stephen Pelc \noun default hat dieses Problem auf der EuroForth angesprochen, und gefordert \begin_inset Quotes gld \end_inset Standardize OOP Now! \begin_inset Quotes grd \end_inset Das Thema führte dann am Ende der Konferenz noch zu zwei Workshops und nach der Konferenz zu weiterer Diskussion per Mail, über die ich hier ausführli cher berichte: \noun on Andrew Haley \noun default bringt dazu zwei Sachen ins Spiel: Zum einen die \begin_inset Quotes gld \end_inset Design Patterns, \begin_inset Quotes grd \end_inset deren Implementierung mit einem brauchbaren OOP möglich sein muss, zum anderen das Metaobject Protocol \begin_inset CommandInset citation LatexCommand cite key "mop" \end_inset , mit dem die Common--Lisp--Leute ihr sehr ähnliches Problem gelöst haben (auch dafür gab es einen ganzen Sack voller untereinander inkompatiblen OOP--Erweiterungen), und ein Paper, das einen interessanten Ansatz zur Verallgemeinerung bringt. Stephen gefällt Forth meets Smalltalk von \noun on Doug Hoffman, \noun default er möchte das als Basis verwenden. \end_layout \begin_layout Standard Stephen verkennt mit seinem Vorschlag, dass gerade \noun on Doug Hoffman \noun default zentrales Teil des Problems ist (auch wenn FMS nicht mehr so grauenhaft ist wie der Vorgänger Neon). Die Diskussion darüber ging dann auch noch per E--Mail nach dem Meeting weiter, wobei \noun on Klaus Schleisiek Manfred Mahlows \noun default OOP als \begin_inset Quotes gld \end_inset Lösung \begin_inset Quotes grd \end_inset anpries, und seine völlige Unkenntnis über Late Binding und vtables offenbarte. Genau das ist meiner Meinung nach das zentrale Kern--Problem von OOP in Forth: Zu viele Leute verstehen darunter lediglich Strukturen mit einem Namensraum für Funktionen. Nein, OOP ist ein ganzer Sack verschiedener Konzepte, weshalb es eben \emph on nicht \emph default ausreicht, mal eben 10% davon zu implementieren, denn die 10%--Lösungen, die alle jeweils unterschiedliche 10% berücksichtigen, die haben wir ja schon. Leon Wagner bestätigt diese These, denn seiner Meinung nach ist SWOOP völlig ausreichend, auch wenn es bei Late Binding ebenso unbrauchbar ist. Das Argument, das man immer hört, ist \begin_inset Quotes gld \end_inset wir/unser Kunden schreiben damit ernsthafte Programme. \begin_inset Quotes grd \end_inset Nein, das ist nicht die richtige Antwort, weil sich die Situation derzeit wohl so darstellt, dass jedes System eben seine eigenen Stärken und Schwächen hat, und deshalb für die zugehörige Anwendung maßgeschneidert ist --- damit aber nicht durch ein beliebiges anderes ersetzt werden kann. \end_layout \begin_layout Standard Ich habe mich jedenfalls mit ein paar Büchern eingedeckt, und denke jetzt erst mal darüber nach, wie man das Problem richtig löst. Code haben wir genug geschrieben, es ist jetzt Zeit, den wieder wegzuwerfen, und das inzwischen gelernte anzuwenden --- oder, wenn da Defizite vorhanden sind, neues zu lernen. Man muss sich auch im Klaren sein: Die bisher benutzten Systeme werden nicht verschwinden, ihre Syntax und Semantik wird erhalten bleiben. Andrews Vorschlag, ein erweiter- und modifizierbares Grundgerüst zu nehmen, auf dem man dann verschiedene Syntax und Semantik aufbauen kann, scheint mir der einzige brauchbare Ansatz zu sein. Solange ich aber von meinen Mit--Forthern beim Wort \begin_inset Quotes gld \end_inset vtable \begin_inset Quotes grd \end_inset immer ein \begin_inset Quotes gld \end_inset das ist mir zu komplex \begin_inset Quotes grd \end_inset höre, habe ich Bedenken --- das dabei entstehende System wird dann bestimmt als eierlegende Wollmilchsau angesehen, und der Forth--Philosophie widerspreche nd, wird also auch nicht akzeptiert. \end_layout \begin_layout Section Instanz--Variablen, Methoden, Vererbung und Polymorphismus \end_layout \begin_layout Standard Die drei Grundkonzepte von OOP sind Instanz--Variablen, Polymorphismus und Vererbung. Der Satz \begin_inset Quotes gld \end_inset Ein Objekt besteht aus Variablen und Methoden, die auf diese Variablen zugreifen \begin_inset Quotes grd \end_inset scheint überall angekommen zu sein, das ist der gemeinsame Minimal--Konsens, es ist das Verständnis einer um Funktionen erweiterten Datenstruktur, es ist aber nur ein Teil dessen, was OOP ausmacht. Ebenso Konsens scheint über die Fähigkeit zur Vererbung zu bestehen, also dass man diese Strukturen und Methoden nachträglich erweitern kann, wodurch eine Unterklasse entsteht, der zusätzliche Instanz--Variablen hinzugefügt werden können, und die die Methoden der Basisklasse überschreiben kann, wobei \begin_inset Quotes gld \end_inset überschreiben \begin_inset Quotes grd \end_inset bedeutet, dass die veränderten Methoden nur für die Unterklasse gelten. Die in der Basisklasse verankerten und damit allen Unterklassen gemeinsamen Methoden nennt man \begin_inset Quotes gld \end_inset Interface, \begin_inset Quotes grd \end_inset das ist eine Kollektion von \lang english Messages \lang ngerman , die man den Objekten schicken kann (man sendet eine \lang english Message \lang ngerman an ein Objekt, aufgerufen wird dann eine Methode --- \lang english Message \lang ngerman und Methode sind zwei verschiedene Sachen, der Operator, um eine \lang english Message \lang ngerman in eine Methode zu überführen, und damit ausführbar zu machen, heißt \begin_inset Quotes gld \end_inset bind \begin_inset Quotes grd \end_inset ). \end_layout \begin_layout Standard Damit hat man schon ein Werkzeug, das über die natürlichen Fähigkeiten von Forth hinausgeht. \noun on Klaus Schleisiek \noun default hat einmal einen Vortrag über die verschiedenen Adressräume von Microcontroller n und DSPs gehalten, und die Forth--übliche Lösung führt zu einer Explosion der Wörternamen und unwartbaren Programmen --- weil man sich bei jeder Adresse merken muss, ob die jetzt im Flash, im EEPROM, im internen RAM, im X-- oder Y--RAM eines DSPs, im Code--Memory einer \lang english Harward \lang ngerman --Architektur, im externen RAM, im IO--Bereich, in einem über SPI oder I \begin_inset Formula $^{2}$ \end_inset C adressierten externen IO--Baustein oder wo auch immer ist. Führt man hier ein bisschen OOP ein, kann man jeder Variablen die Methoden @ und ! zuordnen, und diese jeweils für die verschiedenen Speicherbereiche unterschiedlich implementieren. Die so definierten Variablen \begin_inset Quotes gld \end_inset wissen, \begin_inset Quotes grd \end_inset wie sie auf @ und ! zu reagieren haben, der Programmierer muss das nicht mehr selbst machen. Die Variablen sind im Quelltext durch ihren Namen referenziert, ihre Klasse ist also bekannt und die Methoden können früh gebunden werden. Wartbarkeit ist wieder erreicht, durch das Prinzip \begin_inset Quotes gld \end_inset \lang english information hiding, \lang ngerman \begin_inset Quotes grd \end_inset denn wo die Variable jetzt liegt, und wie sie angesprochen werden muss ist ihr Privat--Wissen, dem Programmierer, der sie verwendet, kann das jetzt egal sein. Hier spricht man von \lang english \begin_inset Quotes gld \end_inset interfaces \lang ngerman \begin_inset Quotes grd \end_inset (das sind in diesem Beispiel @ und !) und \begin_inset Quotes gld \end_inset \lang english implementations \lang ngerman \begin_inset Quotes grd \end_inset (das sind die jeweiligen Umsetzungen für unterschiedliche Adressräume). Der Code dazu sieht ungefähr so aus (Syntax: Bernd\SpecialChar \- OOF, ich nehme an, dass die forthige Lösung für den Zugriff auf Flash und SPI schon implementiert ist, und nur noch der OOP--Wrapper darum gelegt wird, um das ganze wartbar zu machen). Zur Konflikt--Bereinigung zwischen den Methoden @ und ! und den Forth--Wörtern @ und ! gibt es den Prefix F, der explizit im Forth--Wörterbuch sucht. Man könnte auch dem Vorschlag von \noun on Doug Hoffman \noun default folgen, und allen Messages einen : hinzuzufügen, das ist aber ein Konzept aus einer anderen Sprache. In Forth sind Messages auch einfach nur Forth--Wörter. \end_layout \begin_layout LyX-Code object class memvar \end_layout \begin_layout LyX-Code cell var addr \end_layout \begin_layout LyX-Code method @ \end_layout \begin_layout LyX-Code method ! \end_layout \begin_layout LyX-Code how: \end_layout \begin_layout LyX-Code : init ( addr -- ) addr F ! ; \end_layout \begin_layout LyX-Code : ! ( n -- ) addr F @ F ! ; \end_layout \begin_layout LyX-Code : @ ( -- n ) addr F @ F @ ; \end_layout \begin_layout LyX-Code class; \end_layout \begin_layout Standard Ich verwende memvar im Folgenden auch gleich als Basisklasse, die hier nicht abstrakt ist, sondern konkret --- mit der einfachst möglichen Implementierung. \end_layout \begin_layout LyX-Code memvar class flashvar \end_layout \begin_layout LyX-Code how: \end_layout \begin_layout LyX-Code : ! ( n -- ) addr F @ flash! ; \end_layout \begin_layout LyX-Code class; \end_layout \begin_layout Standard Das Flash beschreiben funktioniert anders, lesen kann man es aber wie normalen Speicher. \end_layout \begin_layout LyX-Code memvar class spivar \end_layout \begin_layout LyX-Code how: \end_layout \begin_layout LyX-Code : ! ( n -- ) addr F @ spi! ; \end_layout \begin_layout LyX-Code : @ ( -- n ) addr F @ spi@ ; \end_layout \begin_layout LyX-Code class; \end_layout \begin_layout Standard SPI liest und schreibt man über einen seriellen Datenbus. Jetzt brauchen wir noch etwas Test--Code: \end_layout \begin_layout LyX-Code here 0 , memvar : a \end_layout \begin_layout LyX-Code $20 spivar : b \end_layout \begin_layout LyX-Code $FFEA flashvar : c \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code $1234 a ! \end_layout \begin_layout LyX-Code a @ c ! \end_layout \begin_layout LyX-Code c @ b ! \end_layout \begin_layout LyX-Code b @ hex. ( sollte $1234 geben ) \end_layout \begin_layout Standard Die meisten mir bekannten Forth--OOP--Systeme implementieren das jetzt als Early Binding. Das, was daraus entsteht, ist kein OOP, sondern \begin_inset Quotes gld \end_inset operator overloading, \begin_inset Quotes grd \end_inset der gleiche Operator auf verschiedene Datentypen angewandt wird unterschiedlich implementiert --- die Datentypen sind ihrerseits aber statisch, also von vornherein bekannt. \end_layout \begin_layout Standard Das ist natürlich noch nicht sonderlich flexibel --- normale Variablen kann man einfach auf den Stack legen, und generische Funktionen können einfach @ und ! darauf anwenden, um etwa +! zu implementieren: \end_layout \begin_layout LyX-Code : +! ( n addr -- ) dup >r @ + r> ! ; \end_layout \begin_layout Standard Man kann nun natürlich einfach +! als Methode für jeden Speicherbereich implementieren, das +! darf auch ruhig jedes Mal gleich aussehen, aber wenn @ und ! früh gebunden werden, muss der Code jedes Mal neu übersetzt werden --- für jede Klasse einmal. Einfacher wäre es, @ und ! würden spät gebunden, also erst zur Laufzeit (in obigem Beispiel ist das so, weil Bernd\SpecialChar \- OOF tatsächlich per Default spät bindet). Diese Eigenschaft nennt man \begin_inset Quotes gld \end_inset Polymorphismus \begin_inset Quotes grd \end_inset , Unterklassen haben unterschiedliche Gestalt, und das Senden der gleichen Message führt zu verschiedenen Aktionen --- wobei dem verwendenden Programm nicht bekannt sein muss, mit welcher Unterklasse es zu tun hat. Wir haben es hier also mit dynamischem Typing zu tun --- der Datentyp (die Klasse) des Objekts ist erst zur Laufzeit bekannt. \end_layout \begin_layout Standard Das (recht klassische und einfache) Design--Pattern, das hier verwendet wird, um das zu implementieren, ist das der \begin_inset Quotes gld \end_inset Indirektion. \begin_inset Quotes grd \end_inset Man kann in der Informatik, so heißt es, jedes Problem durch eine zusätzliche Indirektion lösen --- also indem man einen Pointer benutzt, statt den Wert selbst. \end_layout \begin_layout Standard Die Indirektion, die hier nötig ist, ist die beim Aufruf der Methode. Naheliegend ist es, einfach eine Instanz--Variable für jede Message zu definieren, und dort das xt der Methode zu speichern --- wie bei einem \lang english deferred word \lang ngerman . Man kann das so machen, es verschwendet nur Speicher, denn die Methoden sind ja für alle Objekte einer Klasse gleich. \end_layout \begin_layout Standard Die Lösung dazu ist (wie in der Informatik üblich) eine Indirektion, die als \begin_inset Quotes gld \end_inset vtable \begin_inset Quotes grd \end_inset oder \begin_inset Quotes gld \end_inset \lang english virtual method table \lang ngerman \begin_inset Quotes grd \end_inset bezeichnet wird. Man gibt also jedem Objekt einer Klasse einen Pointer mit, auf eine Datenstrukt ur, in der die Methoden einer Klasse gemeinsam verwaltet werden. Üblicherweise ist das ein Array, d.h. jede Methode ist über einen Index schnell und ziemlich direkt zugreifbar, aber man kann da auch Hash--Tables oder Listen verwenden, wenn etwa das Ziel eine Implementierung ist, bei der jedes Objekt jede Message verstehen kann, und damit ein Array als vtable zu viel Speicherplatz kosten würde. Abbildung \begin_inset CommandInset ref LatexCommand ref reference "fig:Ein-Objekt-der" \end_inset zeigt, wie das im Speicher aussieht. \end_layout \begin_layout Standard \begin_inset Float figure wide false sideways false status open \begin_layout Plain Layout \end_layout \begin_layout Plain Layout \align center \begin_inset Graphics filename vtable.eps lyxscale 60 scale 40 \end_inset \end_layout \begin_layout Plain Layout \begin_inset Caption \begin_layout Plain Layout \begin_inset CommandInset label LatexCommand label name "fig:Ein-Objekt-der" \end_inset Ein Objekt der Klasse memvar und seine vtable \end_layout \end_inset \end_layout \begin_layout Plain Layout \end_layout \end_inset \end_layout \begin_layout Standard Deshalb, um das nochmal deutlich zu machen: Eine vtable ist deshalb getrennt vom Objekt abgelegt, um Speicherplatz zu sparen. Die entscheidende Indirektion ist nicht der Pointer auf die vtable, sondern der Pointer auf die Methode, die aus einem Forth--Wort, das im Kontext des Objekts aufgerufen wird, eine polymorphe Message macht --- eine Art \lang english deferred word \lang ngerman , nur eben nicht als Instanz--Variable, sondern für alle Instanzen einer Klasse gemeinsam. \end_layout \begin_layout Standard Viele objektorientierte Sprachen verstehen unter \begin_inset Quotes gld \end_inset \lang english information hiding \lang ngerman \begin_inset Quotes grd \end_inset , dass der Zugriff auf im Objekt intern verwendete Funktionen von außen nicht gestattet ist. Das widerspricht der Forth--Philosophy \begin_inset Quotes gld \end_inset \lang english don't bury your tools \lang ngerman \begin_inset Quotes grd \end_inset , und muss zumindest für's Debugging abschaltbar sein. Meiner Meinung nach ist das auch ein Missverständnis, denn wirklich gemeint ist, dass man zur Kommunikation mit anderen Objekten ihre Interfaces, nicht ihre Implementierung verwenden soll. Das sind aber alles Regeln, keine Gesetze; Regeln, deren Befolgung meistens sinnvoll ist, und deren Verletzung begründet werden sollte. In Forth ist die Durchsetzung solcher Regeln durch den Compiler nicht üblich. \end_layout \begin_layout Section Design Pattern: Komposition statt Vererbung \end_layout \begin_layout Standard Das Meta--Pattern schlechthin bei den Design--Pattern ist, statt Vererbung die Komposition von Objekten zu verwenden. Vererbung ist sinnvoll, um verschiedene Ausformungen einer Klasse zu bekommen; die Komposition von Objekten ist aber flexibler, und verknüpft ganz unterschied liche Eigenschaften. Vererbung ist ein Kopiervorgang (ungeschlechtlich, wie die Fortpflanzung von Bakterien), Komposition ist im Verhältnis dazu wie Sex --- mit mehreren Teilnehmern, die ihre unterschiedliche Herkunft einbringen. \end_layout \begin_layout Standard Ich möchte das mal am Beispiel eines Dialog--Fensters in MINOS erläutern, was damit gemeint ist. Die beiden Relationen, um die es hier geht, werden \begin_inset Quotes gld \end_inset is--a \begin_inset Quotes grd \end_inset und \begin_inset Quotes gld \end_inset has--a \begin_inset Quotes grd \end_inset bezeichnet. Ein Dialog--Fenster in MINOS \series bold ist \series default eine Komponente (das ist die Klasse, von der es abgeleitet wird). Es \series bold hat \series default mehrere Sachen: Zum einen ein Display--Objekt, in dem es dargestellt wird (das ist üblicherweise ein Fenster). Zum anderen hat es Widgets, in der Regel eine ganze Menge, die ihrerseits in horizontalen und vertikalen Boxen angeordnet sind. Auch für Widgets gelten derartige Beziehung: Ein Widget ist z.B. ein Button. Es hat eine (oder mehrere miteinander verkettete) Aktion(en), die ausgeführt werden, wenn man darauf klickt. Und es hat natürlich auch ein Display, in dem es dargestellt wird. \end_layout \begin_layout Standard Die \begin_inset Quotes gld \end_inset is--a \begin_inset Quotes grd \end_inset --Beziehung wird durch Instantiierung und Vererbung erworben, einmal instantiier t lässt sie sich nicht mehr verändern (ein Button bleibt ein Button). Die \begin_inset Quotes gld \end_inset has--a \begin_inset Quotes grd \end_inset --Beziehung durch Zuweisungen, etwa durch Einhängen in die Liste einer Box. Letzteres erfolgt zur Laufzeit, und kann auch während der Laufzeit geändert werden (es können neue Elemente in eine Box eingehängt werden, oder Elemente daraus gelöscht werden). Das ist sehr dynamisch und sehr flexibel. Das dazu verwendete Konstrukt ist, wie nicht anders zu erwarten, eine Indirekti on, ein Pointer auf ein Objekt. \end_layout \begin_layout Standard Die meisten dieser Design--Pattern funktionieren nur mit late binding, manche brauchen sogar Mehrfachvererbung. Ein umfassendes OOP--System sollte es ermöglichen, alle Pattern auszudrücken; wenn man nur spezielle Anwendungsfälle für einige der Pattern hat, reicht manchmal eine reduzierte Version. Ich liste diese Pattern in der Reihenfolge der Gang--of--Four auf, und erkläre kurz, was damit gemeint ist, sowie welche Fähigkeiten des OOP--Systems nötig sind, um diese Pattern zu implementieren. \end_layout \begin_layout Standard Da Forth eine sehr dynamische Sprache ist, und die Design--Pattern sich auf C++ und Java beziehen, fehlen Design--Pattern, die man in diesen Sprachen einfach nicht machen kann. Man muss also auch dieses hier als Minimal--Konsens verstehen, und durchaus in Erwägung ziehen, dass man das auch anders (und besser) machen kann. \end_layout \begin_layout Subsection Creational Patterns \end_layout \begin_layout Standard Diese Pattern haben das Erzeugen von Objekten zum Thema \end_layout \begin_layout Description Abstract \begin_inset space ~ \end_inset Factory Erzeugt verwandte oder voneinander abhängige Objekte, ohne die konkrete Klasse zu spezifizieren. \end_layout \begin_deeper \begin_layout Standard Beispiel: Wir verwenden obige Klassen, um Variablen in verschiedenen Speicherber eichen zu verwalten, wollen aber den Ort unabhängig von den Variablen selbst spezifizieren. Dazu bauen wir uns einen globalen Status, der entsprechend des aktuell verwendeten Speicherbereichs gesetzt ist, und erzeugen in der Abstract Factory immer die passenden Objekte. Wenn unser ADC jetzt vom SPI--Bereich in den I \begin_inset Formula $^{2}$ \end_inset C--Bereich verschoben wird (z.B. weil er beide Interfaces anbietet, der eine Controller aber SPI und der andere I \begin_inset Formula $^{2}$ \end_inset C verwendet), dann ändern wir nur den Bereich, und lassen den Rest des Quellcode s unverändert. \end_layout \begin_layout Standard Dabei kann es verschiedene Klassen geben, die ausgewählt werden, etwa Klassen für Bytes, für 16-- und 32--Bit--Wörter, die alle gemeinsam abhängig vom gerade gewählten Speicherbereich erzeugt werden können. \end_layout \begin_layout Standard Das OOP--System muss Objekt--Pointer beherrschen und echten Polymorphismus, weil der Aufrufer der Abstract Factory nicht weiß, was für ein Objekt er bekommt. Es ist hilfreich zur Implementierung, wenn Klassen ebenfalls herumgereicht und als Pointer abgelegt werden können (etwa, um eine Klassenmatrix anzulegen). Im Beispiel oben werden die Objekte während der Compilation erzeugt und in anderen Teilen des Programms direkt als benannte Variable verwendet (und da das Binding nach der Erzeugung der Objekte geschieht, auch ggf. mit Early Binding), das ist etwas, was in C++ und Java so gar nicht geht. \end_layout \end_deeper \begin_layout Description Builder Erzeugt komplexe Objekte, etwa zum Konvertieren von einem Dateiformat in ein anderes. \end_layout \begin_deeper \begin_layout Standard Beispiel: Wir wollen ein RTF--Dokument in ASCII oder LaTeX konvertieren. Dazu spezifizieren wir das Ziel, und der Builder erzeugt entweder ein ASCII-- oder ein LaTeX--Dokument--Objekt. Beide Objekte nehmen Text und Formatierungsanweisungen des RTF--Readers entgegen, der ASCII--Builder baut aber nur die Strings in die Ausgabe ein, während der LaTeX--Builder auch die Formatierungsanweisungen übersetzt. \end_layout \begin_layout Standard Auch hier muss das OOP--System Objekt--Pointer und Polymorphismus beherrschen. \end_layout \end_deeper \begin_layout Description Factory \begin_inset space ~ \end_inset Method Erzeugt Objekte, wobei die Klasse durch einen Parameter spezifiziert ist, oder in Unterklassen variiert wird, ähnlich der Abstract Factory, nur dass hier eine Methode verwendet wird, um ein Objekt zu erzeugen. Die Anforderungen an das OOP--System sind die gleichen wie bei der Abstract Factory \end_layout \begin_layout Description Prototype Hier wird ein Objekt kreiert, in dem man eine Instanz, den Prototypen, spezifiziert, und neue Objekte erzeugt, indem man den Prototyp kopiert. \end_layout \begin_deeper \begin_layout Standard Die wesentliche Forderung an das OOP--System ist, dass es den clone--Operator implementieren kann, und dass Objekte während der Laufzeit neue Instanz--Variab len und Methoden bekommen können --- dann ist das Prototyp--Pattern direkt im System implementiert. \end_layout \end_deeper \begin_layout Description Singleton Eine Klasse, die nur genau einmal instantiiert werden kann; dieses eine Objekt muss global verfügbar sein. Die Instantiierung erfolgt beim ersten Zugriff, nicht beim Programmstart. \end_layout \begin_deeper \begin_layout Standard Die Forderung an das OOP--System hier ist, globale Variablen innerhalb einer Klasse zu ermöglichen, und Methoden, die schon vor der Instantiierung aufgerufe n werden können --- diese Methoden können nicht late binding sein. \end_layout \end_deeper \begin_layout Subsection Structural Patterns \end_layout \begin_layout Description Adapter Ein Adapter konvertiert die Aktionen eines Interfaces in ein anderes, um verschiedene bereits existierende Programme aneinander anzupassen. \end_layout \begin_deeper \begin_layout Standard Beispiel: Eine Grafik--Ausgabe mit einem karthesischen Koordinatensystem soll mit einem Adapter in eine Turtle--Grafik umgesetzt werden, weil ein anderes existierendes Objekt eine Turtle--Grafik erwartet. Das Adapter--Objekt wird also die Position und Richtung der Turtle als Zustandsvariablen enthalten, und aus forward/backward eine entsprechende lineto--Message berechnen. \end_layout \begin_layout Standard Ein Adapter kann entweder durch Mehrfachvererbung (Class Adapter) oder durch Komposition (Object Adapter) erzeugt werden. \end_layout \end_deeper \begin_layout Description Bridge So ähnlich wie ein Adapter, aber von vornherein im Entwurf so vorgesehen. \end_layout \begin_deeper \begin_layout Standard Wenn die Turtle--Grafik im obigen Beispiel von vornherein Design--Ziel ist (wir wollen das als stabiles Interface für den User zur Verfügung stellen), und die Grafik--Ausgabe je nach Ausgabe--Device das mehr oder weniger direkt unterstützt (X Window System schlecht, OpenGL mäßig, PostScript gut), dann sind die Objekte, die das konvertieren, Bridges, nicht Adapter. \end_layout \end_deeper \begin_layout Description Composite Erlaubt es, Objekte zusammenzusetzen, und diese zusammengesetzten Objekte ihrerseits genauso wie einzelne Objekte zu behandeln. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Hier gibt es Widgets und Boxes, und natürlich sind Boxes ihrerseits wieder Widgets, die eben mehrere andere Widgets enthalten. \end_layout \begin_layout Standard Das erfordert Objekt--Pointer und Late Binding. \end_layout \end_deeper \begin_layout Description Decorator Fügt zusätzliche Verantwortlichkeit dynamisch zu einem Objekt hinzu. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Die Aktionen, die ein Widget hat, können etwa mit einem Tooltip--Objekt dekoriert werden. Die Aktion selbst ist unverändert (ein Klick produziert das gleiche wie ohne Tooltip), aber wenn der Benutzer die Maus über dem Widget stehen lässt, wird ein Tooltip angezeigt. \end_layout \begin_layout Standard Auch hier ist man mit Objekt--Pointern und Late Binding dabei. \end_layout \end_deeper \begin_layout Description Facade Stellt ein \begin_inset Quotes gld \end_inset einfaches \begin_inset Quotes grd \end_inset Interface (in einer Klasse) zur Verfügung, die in Wahrheit über eine ganze Kollektion verschiedener Objekte implementiert wird. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Ein Slider besteht aus Pfeilen nach oben und unten, einem abgesenkten Bereich und einem Slider darin, der den sichtbaren Ausschnitt des Dokuments repräsentiert. Nach außen stellt sich der Slider als ein Objekt dar, das die Position und den sichtbaren Ausschnitt des Dokuments erfasst und verändern kann. \end_layout \begin_layout Standard Je nach Anwendungsfall kann die Facade auch mit Objekt--Instanzvariablen und Early Binding oder mit Objekt--Pointern und Late Binding implementiert werden. \end_layout \end_deeper \begin_layout Description Flyweight Verwendet Objekte gemeinsam, um eine große Zahl von Objekten effizient zu verwalten. \end_layout \begin_deeper \begin_layout Standard Beispiel: Die vtable eines Objektes kann man ja auch als Objekt auffassen. Wie oben beschrieben, ist es sinnvoll, alle Objekte in einer Klasse auf dieselbe vtable zeigen zu lassen, statt die vtable für jedes Objekt zu duplizieren. In einem prototyp--basierten OOP ist es aber möglich, einzelne Objekte später zu ändern, und neue Methoden hinzuzufügen --- dann, aber erst dann, muss die vtable kopiert werden. Die Gang of Four gibt als Beispiel eine Textverarbeitung an, die jeden Buchstaben als Objekt (mit Bounding Box und grafischer Darstellung) speichert. Jeden Buchstaben für sich natürlich nur einmal, um Speicher zu sparen. \end_layout \begin_layout Standard Zwingend notwendig: Objekt--Pointer. \end_layout \end_deeper \begin_layout Description Proxy Ein Platzhalter für ein Objekt, um den Zugang zu kontrollieren. \end_layout \begin_deeper \begin_layout Standard Proxies werden auf vielerlei Weise eingesetzt; das Beispiel, das Andrew Haley erwähnte, ist, um das Erzeugen des Objekts zu verzögern. Eine Textverarbeitung kann einen Proxy nehmen, um das Laden und Darstellen eines Bildes zu verzögern --- solange der Benutzer die Seite mit dem Bild nicht anzeigt, existiert nur der Proxy, der die Größe des Bildes dem Umbruchalg orithmus übergibt. Erst, wenn die draw--Methode des Proxies aufgerufen wird, wird das eingebundene Bild komplett geladen und dargestellt (das dauert und kostet Speicherplatz, will man längere Dokumente bearbeiten, ist es sinnvoll, das nur bei Bedarf zu erledigen --- der Speicher nicht mehr sichtbarer Bilder kann dann auch wieder freigegeben werden). Auch die im Flyweight beschriebenen Buchstaben--Objekte werden ein Proxy--Objek t benötigen, das z.B. die Position speichert. \end_layout \begin_layout Standard Ein Proxy kann auch Zugangsbeschränkungen implementieren, etwa verhindern, dass eine Datenbank manipuliert wird, wenn sich der User nicht eingeloggt hat. Der Proxy implementiert in diesem Fall den Login--Vorgang, und reicht schreiben de Zugriffe erst nach einem erfolgreichen Login auf das Datenbankobjekt durch. Ein Proxy kann aber auch verwendet werden, um Objekte über's Netz anzusprechen. \end_layout \begin_layout Standard Objekt--Pointer sind hier zwingend erforderlich; je nach Anwendungsfall kann von vornherein bekannt sein, welches Objekt der Proxy ersetzt (Early Binding möglich), oder auch nicht. \end_layout \end_deeper \begin_layout Subsection Behavioral Patterns \end_layout \begin_layout Description Chain \begin_inset space ~ \end_inset of \begin_inset space ~ \end_inset Responsibility Mehrere Objekte in einer Kette bekommen die gleiche Eingabe serviert, bis eines darauf reagiert. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Das Text--Eingabefeld muss auf Cursor--Tasten und ähnliches reagieren. Jeder derartigen Taste ist ein Objekt zugeordnet, das entsprechend reagiert. \end_layout \begin_layout Standard Beispiel Recognizer: Die Recognizer, die \noun on Matthias Trute \noun default in amForth eingebaut hat, können als Chain of Responsibility aufgefasst werden --- jeder Recognizer sieht sich das Forth--Wort an, und reagiert entsprechend --- wenn es im Wörterbuch ist, wird es ausgeführt oder compiliert, wenn es eine Zahl ist, umgewandelt, und auf den Stack gelegt bzw. als Literal compiliert. \end_layout \begin_layout Standard Dieses Pattern benötigt Object--Pointer und Late Binding, es kann auch sinnvoll sein, deferred words als Instanz--Variablen zu ermöglichen. \end_layout \end_deeper \begin_layout Description Command Macht aus einem Kommando ein Objekt. Die Methode, die ein command--Objekt zur Verfügung stellt, ist execute, es kann also ausgeführt werden. Was es dabei tut, ist seine Sache. Es kann auch mehrere Varianten von execute geben. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Die Aktionen, die ein Widget hat, rufen ganz spezifischen Code auf (im Kontext eines anderen Objekts), haben aber ein gemeinsames Interface. Kommandos sind die OO--Version von Callbacks. \end_layout \begin_layout Standard Beispie Forth: Wörter sind Kommandos; folgt man der Idee des \begin_inset Quotes gld \end_inset smart compile, \begin_inset Quotes grd \end_inset , dann ist ein Wort auch tatsächlich ein richtig komplexes Objekt, das ausgeführ t, interpretiert, compiliert und mit postpone später compiliert werden kann. Das geht über die einfache Struktur eines Command--Objekts schon deutlich hinaus. \end_layout \begin_layout Standard Objekt--Pointer und Late Binding sind zwingend erforderlich, deferred words hilfreich. Auch hilfreich ist es, ein Stück Code im Kontext eines Objekt--Pointers auszuführen, also dort mehrere Methoden aufzurufen, ohne jedesmal zwischen dem Aufrufer und dem aufgerufenen Objekt umzuschalten (Multi--Message). \end_layout \end_deeper \begin_layout Description Interpreter Erlaubt es, eine (einfache) Sprache als abstrakter Syntax--Baum zu implementieren. Dieses Pattern ist für Forth--Nutzer wohl eher uninteressant, da wir einfache Sprachen direkt in Forth implementieren, und komplexere Sprachen einen Parser--Generator benötigen, der von dem Pattern nicht umfasst wird. \end_layout \begin_layout Description Iterator Ein Iterator durchläuft zusammengesetze Objekte sequenziell, ohne die innere Struktur des Objekts offenzulegen (also unabhängig davon, ob es ein Array oder eine Liste ist). \end_layout \begin_deeper \begin_layout Standard Der Iterator wandelt eine Klasse ab, also ist entweder Mehrfachvererbung oder die Zuordnung eines bereits definierten Interfaces zur Klasse hilfreich. Late Binding ist ebenso zwingend erforderlich \end_layout \end_deeper \begin_layout Description Mediator Ein Mediator ist ein Objekt, das die Kommunikation zwischen verschieden en Objekten zentral behandelt, damit die einzelnen Objekte nichts voneinander wissen müssen. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Das Komponenten--Objekt, das Dialoge implementiert, ist auch ein Mediator zwischen den einzelnen Objekten im Dialog. Die Kommandos werden alle an den Mediator gesendet, der weiß, wie die verschied enen Objekte miteinander interagieren. \end_layout \begin_layout Standard Objekt--Pointer sind zwingend erforderlich, je nach notwendiger Flexibilität des Mediators kann aber Early Binding ausreichen. \end_layout \end_deeper \begin_layout Description Memento Erfasst und speichert den Zustand eines Objekts, um es später zu restaurieren. \end_layout \begin_deeper \begin_layout Standard Beispiel: Um die Undo--Operation in einem Editor zu implementieren, speichert das Memento bei jedem Backspace das gelöschte Zeichen und dessen Position im Text. Führt man später Undo aus, werden diese Zeichen wieder an der richtigen Stelle eingefügt. \end_layout \begin_layout Standard Objekt--Pointer und Late Binding sind erforderlich. \end_layout \end_deeper \begin_layout Description Observer Wenn der Zustand eines Objekts sich ändert, werden alle abhängigen Objekte benachrichtigt. \end_layout \begin_deeper \begin_layout Standard Beispiel Facebook: Wenn man einen Eintrag auf seine Pinwand schreibt, werden alle Freunde benachrichtigt, und bekommen den Eintrag in ihren Neuigkeiten zu sehen. \end_layout \begin_layout Standard Objekt--Pointer, Late Binding und zumindest Interfaces (ggf. auch Mehrfachvererbung) sind nötig. \end_layout \end_deeper \begin_layout Description State Dieses Pattern beschreibt eine State--Maschine, wobei für jeden Zustand eine andere Klasse verwendet wird --- die Funktionen zum Ändern des Zustands sind die Methoden der Zustands--Objekte, sie ändern sich abhängig vom Zustand. \end_layout \begin_deeper \begin_layout Standard Das State--Pattern kann direkt in einem OOP--System implementiert werden, wenn es möglich ist, die Klasse des Objekts zur Laufzeit zu ändern (durch Ändern des vtable--Pointers). \end_layout \end_deeper \begin_layout Description Strategy Definiere eine Familie von Algorithmen, die austauschbar sind. \end_layout \begin_deeper \begin_layout Standard Beispiel: Ein Roboter sucht sich einen Weg, und verwendet dabei je nach Situation unterschiedliche Algorithmen. Auf freiem Feld kann er etwa den kürzesten Weg zum Ziel berechnen, in einem Labyrinth muss er das Terrain erkunden und eine Karte erzeugen. \end_layout \begin_layout Standard Objekt--Pointer und Late Binding sind erforderlich. \end_layout \end_deeper \begin_layout Description Template \begin_inset space ~ \end_inset Method Definiert das Skelett eines Algorithmus, der dann in Unterklassen verfeinert wird. \end_layout \begin_deeper \begin_layout Standard Beispiel Forth: Compiler und Interpreter parsen jeweils ein Wort aus dem Eingabestrom, bearbeiten das dann aber unterschiedlich. Statt STATE @ IF .. ELSE .. THEN zu schreiben, definiert man einen Hook, der dann in den Unterklassen compiler und interpreter implementiert wird. \end_layout \begin_layout Standard Late Binding ist erforderlich. \end_layout \end_deeper \begin_layout Description Visitor Eine Operation auf alle Elemente eines Composite. \end_layout \begin_deeper \begin_layout Standard Beispiel MINOS: Bei der Formatierung der Objekte wird jedes Objekt in einer Box nach minimaler und maximaler Ausdehnung gefragt, und daraus berechnet, welche Position und Größe es in der Box haben wird. \end_layout \begin_layout Standard Objekt--Pointer und Late Binding sind erforderlich, die Möglichkeit, mehrere Methoden im Kontext eines Objekt--Pointers hintereinander aufzurufen, hilfreich. Es ist auch hilfreich, wenn man Teile eines Wortes innerhalb einer impliziten Schleife ausführen kann --- in MINOS verwende ich dafür Return--Stack--Tricks. Ebenfalls nützlich ist eine Tail--Call--Optimization, um Returnstack--Platz zu sparen. \end_layout \end_deeper \begin_layout Section Was bleibt zu tun \end_layout \begin_layout Standard Ich habe mein OOP ( \begin_inset Quotes gld \end_inset Bernd\SpecialChar \- OOF \begin_inset Quotes grd \end_inset ) schon ein paar Jahre vor der Veröffentlichung des Design--Patterns--Buch geschrieben, und zum Teil erst hinterher so erweitert, dass die meisten Design--Pattern implementierbar sind. Manchmal nicht ganz so elegant, wie man sich das wünscht, manchmal auf eine sehr forthige Art, die zumindest den Compiler von VFX Forth überfordert (das Visitor--Pattern wird in MINOS durch eine implizite Schleife implementiert , die am Returnstack herummanipuliert). Die Implementierung eines OOP--Systems ist leider immer \begin_inset Quotes gld \end_inset Guru Code, \begin_inset Quotes grd \end_inset wie Stephen Pelc es ausdrückt; es ist nichts offensichtlich, es muss alles umfangreich dokumentiert werden; da ein neues Programmier--Paradigma implementi ert wird, kann man sich nicht auf gemeinsame Kenntnisse verlassen. Das ist bei praktisch keinem existierenden OOP--System wirklich der Fall, jedenfalls nicht in dem nötigen Ausmaß. Auch wenn Bernd\SpecialChar \- OOF meiner Ansicht nach verwendbar ist, und die anderen OOP--Systeme für Forth zu viele Mängel haben, ist es keine Lösung für das Problem, das wir haben. Es ist auch nicht wirklich portabel, die Implementierung einer performanten Lösung ist nicht trivial, und ein signifikanter Teil des VFX--Compilers (der Inliner) musste komplett neu geschrieben werden, um das richtig zu compilieren (das war aber eine Aktion, die ohnehin notwendig war). \end_layout \begin_layout Standard Ich finde den Common--Lisp--Ansatz des Metaobjekt--Protokolls sehr interessant, und werde versuchen, etwas ähnliches in Forth zu implementieren. Die Idee dahinter ist, das OOP--System selbst unter Verwendung objektorientiert er Programmierung zu implementieren, und so die notwendige Flexibilität zu erreichen. Als Implementierungsbasis, also zum Bootstrappen des OOPs, werde ich mein Mini--OOP verwenden, die 12 Zeilen, die Vtables und Instanz--Variablen implementieren, mehr aber nicht. Ziel ist, dass man damit dann Syntax und Semantik bestehender OOP--Systeme, also etwa von SWOOP, FMS, Bernd\SpecialChar \- OOF und anderen implementieren kann, und diese Systeme auch jederzeit erweitern kann (etwa um Mehrfachvererbung), ohne wie bisher intime Kenntnis über die jeweiligen Systeme zu haben --- nur die Kenntnis des Metaobjekt--Protokolls ist natürlich zwingend nötig. \end_layout \begin_layout Standard Es soll im so entstehenden System möglich sein, Klassen aus verschiedenen OOP--Systemen zu verknüpfen, und gemeinsam zu verwenden. Dabei muss es möglich sein, dass die Implementierung deutlich voneinander abweicht --- Bernd\SpecialChar \- OOF z.B. hat eine C++/Java--artige Klassenhierarchie, in der jedes Objekt nur die Messages versteht, die es entweder geerbt oder selbst definiert hat. Andere Messages werden schon zur Compile--Zeit abgewiesen. FMS dagegen implementiert das Smalltalk--Model, bei der jedes Objekt prinzipiel l jede Message versteht, zumindest über die \begin_inset Quotes gld \end_inset kannitverstan \begin_inset Quotes grd \end_inset --Methode, die aber erst zur Laufzeit ausgeführt wird, und eine Fehlermeldung produziert. Die vtables in Bernd\SpecialChar \- OOF implementiert man am besten als Arrays (da sie immer dicht besetzt sind, die kompakteste Darstellung im Speicher), die vtables von FMS eher als Listen oder Hashes, da sie dünn besetzt sind (die meisten Klassen implementieren nur wenige Messages, und verstehen die vielen anderen Messages nicht). \end_layout \begin_layout Standard Es soll auch möglich sein, degenerierte Klassen und Objekte zu erzeugen, die eben nur Early Binding können und keinen vtable--Pointer haben, weil viele Forth--Programmierer offensichtlich damit glücklich sind. Die einzelnen Fähigkeiten eines kompletten OOP--Systems sollten getrennt voneinander implementierbar sein, und als Erweiterungen betrachtet werden können. Wenn ich also z.B. Multiple Inheritance brauche (Bernd\SpecialChar \- OOF kann das derzeit nicht), dann lade ich es einfach dazu. \end_layout \begin_layout Standard Die notwendigen Primitives, also der Zugriff auf Instanz--Variablen über einen this/self--Pointer, die performante Ausführung von bind(message) über vtables (Arrays und Listen/Hashes), und die Erweiterbarkeit des äußeren Interpreters um Namensräume für Klassen müssen von der eigentlichen Syntax und Semantik des OOP--Systems getrennt werden können, damit man nur diesen Low--Level--Teil portieren und für jedes Forth--System extra warten muss. \end_layout \begin_layout Bibliography \begin_inset CommandInset bibitem LatexCommand bibitem key "gof" \end_inset \noun on Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: \emph on \noun default Desing Patterns: Elements of Reusable Object--Oriented Software \end_layout \begin_layout Bibliography \begin_inset CommandInset bibitem LatexCommand bibitem key "ca" \end_inset \noun on Christopher Alexander, Sara Ishikawa, Murray Silverstein, Max Jacobson, Ingrid Fiksdahl--King, Shlomo Angel: \emph on \noun default A Pattern Language \end_layout \begin_layout Bibliography \begin_inset CommandInset bibitem LatexCommand bibitem key "tf" \end_inset \noun on Leo Brodie, \emph on \noun default Thinking Forth \end_layout \begin_layout Bibliography \begin_inset CommandInset bibitem LatexCommand bibitem key "mop" \end_inset \noun on Gregor Kiczales, Jim des Rivières, Daniel G. Bobrow, \emph on \noun default The Art of the Metaobject Protocol \end_layout \begin_layout Standard \begin_inset ERT status open \begin_layout Plain Layout \backslash end{multicols} \end_layout \end_inset \end_layout \end_body \end_document