A.5 CLOS
CLOS steht für Common Lisp Object System und wird meistens als C-LOS (und nicht KLOS) ausgesprochen. CLOS ist eine objektorientierte Erweiterung zu Common Lisp, einer im Kern funktionalen Programmiersprache. Ähnlich wie C++ als Zusatz zu C entwickelt wurde, übernimmt CLOS alle Sprachkonstrukte von Common Lisp und stellt zusätzliche Möglichkeiten für objektorientierte Programmierung zur Verfügung.
In der Praxis ist die Bedeutung von CLOS eher gering, die Sprache wurde vor allem im Universitäts- und Forschungsbereich angewendet. Allerdings ist in CLOS eine Reihe von innovativen Konzepten enthalten, die in andere Sprachen eingeflossen sind. Auch die Kombination mit der dynamisch typisierten Sprache Common Lisp bietet interessante Möglichkeiten.
Ergänzt wird CLOS in vielen Implementierungen durch eine Umsetzung eines Metaobjekt-Protokolls (MOP). Dieses erlaubt Anpassungen der Sprache, um diese an unterschiedliche Anforderungen anzupassen.
Struktur von CLOS
Da CLOS auf Common Lisp basiert, ist es wie dieses dynamisch typisiert.
Operationen werden über sogenannte generische Funktionen (Generic Functions) definiert. Eine Methode implementiert eine generische Funktion für eine bestimmte Menge von Parametertypen. Methoden sind also nicht genau einer Klasse zugeordnet. Vielmehr wird beim Aufruf einer generischen Funktion anhand der Werte aller übergebenen Parameter bestimmt, welche Methode verwendet wird. Da Methoden damit nicht klassengebunden sind, ist eine Erweiterung um neue Operationen und Methoden also möglich, ohne den Source-Code von existierenden Klassen anpassen zu müssen.
Mehrfachvererbung von implementierenden Klassen ist in CLOS möglich. Dabei erben die abgeleiteten Klassen die Datenelemente der Basisklassen. Wir können allerdings nicht direkt davon sprechen, dass auch die Methoden der Basisklasse erben, da diese ja nicht einer einzigen Klasse zugeordnet werden müssen.
Syntax von CLOS
(defclass NamePart (...)) (defclass VersionNumber (NamePart) ((parts :initform nil :initarg :parts :accessor parts))) (defgeneric toString (printable)) (defgeneric compareTo (comparable)) (defmethod toString ((printable VersionNumber)) (let ((string "")) (dolist (item (parts printable)) (if (equal string "") (setf string (format nil "~A" item)) (setf string (format nil "~A.~A" string (format nil "~A" item))))) string)) (defmethod compareTo ((comparable VersionNumber)) ;; Hier erfolgt die Implementierung von compareTo ) (defun ausgabe() (let* ((num (make-instance 'VersionNumber :parts '(6 0 2800 1106)))) (toString num))) [2]> (ausgabe) "6.0.2800.1106" [3]>
- Wir deklarieren eine Klasse VersionNumber.
- Sie erbt von der Klasse NamePart.
- Jedes Exemplar dieser Klasse enthält eine Variable mit dem Namen parts. Der Datentyp ist nicht festgelegt. Die Angabe von initform legt fest, dass diese Variable standardmäßig mit dem Wert nil vorbelegt wird. Die Angabe von :initarg legt fest, dass bei der Konstruktion auch ein anderer Wert angegeben werden kann. Der Name des betreffenden Parameters ist dann :parts. Der Zugriff auf die Variable erfolgt über den sogenannten Accessor, der ebenfalls parts heißt.
- toString und compareTo werden als Operationen (generische Funktionen) deklariert. Dadurch können Methoden zur Umsetzung der Operationen implementiert werden, deren Aufruf über den Mechanismus der Polymorphie gesteuert wird.
- Die Methode toString implementiert die Operation toString für Exemplare der Klasse VersionNumber.
- Über (let ((string "")) wird eine lokale Variable string deklariert und mit dem Leerstring vorbelegt. Der Sichtbarkeitsbereich ist durch die umgebenden Klammern festgelegt.
- dolist führt eine angegebene Funktion für alle Elemente einer Liste aus. In diesem Fall erfolgt eine Ausgabe des Listenelements item für alle Elemente der Liste, die über den Accessor-Aufruf (parts printable) geliefert wird.
- Die Methode toString liefert den Wert der lokalen Variablen string als Ergebnis zurück.
- Über defun wird eine Funktion definiert, in diesem Fall eine einfache Funktion, die eine Versionsnummer konstruiert und ausgibt.
- Über make-instance wird ein Exemplar von VersionNumber konstruiert, mit den Bestandteilen für eine Versionsnummer initialisiert und der Variablen num zugewiesen. Über den Zugriff mit toString wird das Exemplar dann als String formatiert und dieser String als Ergebnis der Funktion zurückgegeben.
Ressourcen
Eine freie Implementierung von Common Lisp ist das unter http://clisp.cons.org/ verfügbare CLISP. CLISP ist für eine Reihe von Plattformen, darunter auch Microsoft Windows, verfügbar.
Eine sehr gute Übersicht über Common Lisp bietet Common LISP: The Language von Guy L. Steele [Steele 1990]. Eine Online-Version ist verfügbar unter http://www.supelec.fr/docs/cltl/clm/clm.html. Eine Beschreibung von CLOS und dem Metaobjekt-Protokoll findet sich in The Art of the Metaobject Protocol von Gregor Kiczales, Jim des Rivičres und Daniel Bobrow. [Kiczales 1991]
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.