7  Fazit

Clojure zu lernen ist ein spannendes Abenteuer. Wer bereits über Erfahrungen mit Lisp – vor allem Common Lisp – verfügt, wird einige liebgewonnene Spracheigenschaften vermissen, aber neue entdecken. Für Programmierer ohne Erfahrungen mit Lisp oder funktionaler Programmierung bedeutet der Einstieg in Clojure einen viel größeren Umbruch. Die Möglichkeit, ganz neue Konstrukte und Methoden zu lernen, ist für manche Grund genug, eine neue Programmiersprache in Angriff zu nehmen.

 7.1  Kritik
 7.2  Clojures Zukunft
 7.3  Vorhang

7.1  Kritik

Clojure enthält zahlreiche interessante Features, es ist aber andererseits auch noch jung und in einigen Bereichen noch nicht ausgereift. Gerade Common Lisp trägt durch sein Alter viel Geschichte mit sich herum, die auch dazu geführt hat, dass viele Sonderfälle ans Tageslicht getreten sind und gelöst wurden. Aber auch Java hat ausreichend Jahre und Anwendungsfälle auf dem Buckel, dass es seine Kinderkrankheiten durchlebt haben dürfte. Clojure muss diese Phase der Entwicklung erst noch durchlaufen, auch wenn es durch sein Erbe von Lisp und Java sehr stabil ist. Vor allem in den Bereichen, in denen Clojure Neuland betritt, ist noch mit Ecken und Kanten zu rechnen. BlogsDie Neigung vieler Programmierer, sich in Form eines Blogs der Welt mitzuteilen, erlaubt es, uns einen Eindruck zu verschaffen, wie Clojure aufgenommen wird und, für diesen Abschnitt relevant, welche Teile auf Kritik stoßen.

Debuggen

Einer der größten Kritikpunkte ist die Schwierigkeit des Debuggens. Das liegt vor allem daran, dass die Stacktraces, die im Falle einer Exception angezeigt werden, in den seltensten Fällen geeignet sind, die Ursache der Exception zu ermitteln. Wer einmal einen Stacktrace von Common Lisp untersucht hat, in dem es möglich ist, sich jede lokale Variable, jedes Argument, jede Funktion bis hin zum kompilierten Code einer Funktion anzuschauen, wird von Javas Stacktraces sehr enttäuscht sein. Hinzu kommt, dass durch die Codeerzeugung durch Bytecode-Manipulation (siehe auch Abschnitt 4.8) der Bezug zum Clojure-Code oft zusätzlich verschleiert wird. Hier muss die Entwicklergemeinschaft von Clojure dringend Lösungen finden, da dieses Problem das Potenzial hat, die Verbreitung von Clojure massiv zu behindern. Die Clojure-Gemeinde ist sich dessen bewusst und in jüngerer Vergangenheit wurden in dieser Hinsicht bereits Fortschritte gemacht. Debuggen mit den etablierten Java-Werkzeugen ist prinzipiell möglich, wie Abbildung 7.1 demonstriert, aber auch dies ist noch etwas hakelig in der Verwendung. Ein gelungene Verbindung der Werkzeuge, die die JVM anbietet, mit den Vorgehensweisen aus der Lisp-Welt erscheint wünschenswert.

Abbildung 7.1: Netbeans mit Enclojure-Plugin und aktiviertem Debugger
PIC

Bruch mit Konventionen

Rich Hickey hat für viele Entscheidungen, die mit bisherigen Lisp-Konventionen brechen, gute Erklärungen. Die Entscheidung, das Komma als Whitespace zu betrachten, fällt nicht in diese Gruppe. Die Vorteile sind gering (Gewohnheit der Java-Programmierer und marginale Verbesserung der Lesbarkeit durch Gruppieren von Schlüssel-Wert-Paaren bei Maps), die Nachteile wiegen aber auch nicht schwer (Bruch mit Lisp-Konvention, die das Komma in Makros so verwendet wie Clojure die Tilde, umstrittene Verschlechterung der Lesbarkeit von Makrodefinitionen), so dass dieser Punkt als relativ unwichtig betrachtet werden dürfte. Ebenso die Einbeziehung von eckigen und geschweiften Klammern, deren korrekte Verwendung an den meisten Codestellen leicht von den Fingern geht, aber vor allem beim Schließen tief geschachtelter Codeteile störend auffällt.

Lisp-1 vs. Lisp-2

Clojure ist ein „Lisp-1“, bei dem sich Variablen und Funktionen den gleichen Namensraum teilen, Common Lisp hingegen ist ein „Lisp-2“, für das dies nicht gilt. Zusammen mit der Neigung von Lisps, kurze und prägnante Funktionsnamen zu vergeben, führt das dazu, dass die „guten“ Namen für lokale Variablen oft schon vergeben sind. Das führt zwar nur dann zu einem Problem, wenn die Funktion gleichen Namens zur Anwendung kommen soll, kann aber Leser der Funktion verwirren. Andererseits hat diese Entscheidung auch Vorteile. Wo immer Funktionen verwendet werden, braucht es keine explizite Syntax oder Aufrufe. Anstatt eine Funktion in einer Variablen zu speichern und funcall mit dieser aufzurufen, kann die Variable direkt an Stelle des Funktionsnamen stehen.

Endrekursion

Fehlende Endrekursion wird ebenfalls oft genannt und mit der fehlenden Funktion in der JVM begründet. Doch geht dieses Argument nicht weit genug, denn Clojure kann die explizite Rekursion mit loop und recur optimieren, was unter Umständen auch auf „echte“ Endrekursion erweitert werden könnte. In der Arbeit mit Clojure erweist sich die Form als gut zu verwenden und unserer Meinung nach ist sie sogar vorteilhaft, gerade weil sie die Intention explizit ausdrückt. Sie kann so auch durch den Compiler überprüft werden und ist für den Leser leichter zu erkennen.

Metadaten, Typsystem

Die Tatsache, dass Metadaten auf Clojure-Typen beschränkt sind, ist derzeit wohl am ehesten durch die Implementation von Metadaten innerhalb der jeweiligen Klassen zu erklären. Eine Alternative für Java-Objekte könnte darin bestehen, deren Metadaten in einer externen Datenstruktur zu halten. Diese Aussage spiegelt jedoch nicht die Meinung der Clojure-Entwickler, sondern unsere Auffassung zur Implementation wider. Eng verwandt mit Metadaten ist die explizite Angabe des Typs einer Variablen. Diese wird allgemein als eher unschön oder gar hässlich empfunden. Diskussionen auf der Mailingliste deuten darauf hin, dass sich die kommende Version von Clojure mit Optimierungen im Typsystem beschäftigen wird. Ob ein System zur Typinferenz nach Art von Hindley-Milner, wie es etwa in Haskell und Scala zu finden ist, in Clojure verwendet werden könnte, etwa um für den Anwender unbemerkte Optimierungen durchzuführen, bleibt anzuwarten.

JVM, STM

Vor allem von Entwicklern, die Common Lisp favorisieren, kommt Kritik am Einsatz der JVM. Andere führen dies als ausdrücklichen Vorteil von Clojure an. Somit ist der Einsatz der JVM nicht unumstritten. Gleiches gilt für das STM-System. Hier kommt Kritik in erster Linie von erfahrenen Entwicklern, die Locking gut beherrschen und ihre Probleme damit lösen können.

Mehr Quellen

Ein Ausgangspunkt für die Suche nach Meinungen und Kritik zu Clojure ist der Blogeintrag von Stephen Bach [5]. Zwei andere lesenswerte Quellen sind die Diskussion um „Multithreaded Memoize“, die Meikel Brandmeyer zusammengefasst hat [9] sowie ein Thread in der Clojure-Gruppe, in dem es um langlaufende Transaktionen geht [61]. In diesen Diskussionen wurden die Hintergründe der STM-Maschinerie und Probleme beim Multithreading umfassend besprochen. Unabhängig von den jeweiligen Resultaten dieser Diskussionen sieht es für uns so aus, als würde Clojure seinem Anspruch, Multithreading für die Massen leicht verfügbar zu machen, noch nicht ganz gerecht. Teilweise ist noch zu viel Hintergrundwissen notwendig, um STM korrekt einzusetzen. Hier wird sich im Laufe der Zeit sicherlich noch einiges tun, zumal auch die Performance der STM noch nicht flächendeckend getestet ist.

7.2  Clojures Zukunft

Clojure enthält heute einige interessante neue Technologien: die persistenten Datenstrukturen und vor allem STM. Mit Spannung erwarten wir den weiteren Verlauf und ob sich diese Technologien werden durchsetzen können. Auch die Frage, inwieweit sich die Einführung von Protokollen und Datentypen auf die Entwicklung der Sprache auswirken wird, ist offen.

Projekte

Clojure in Clojure ist sicherlich ein wichtiges nächstes Projekt, aber auch die Entwicklung einer wichtigen Applikation in Clojure steht noch aus. Gemeinhin gilt das als ein weiteres Kriterium dafür, ob sich eine Sprache durchsetzen kann, und dieser Test steht bei Clojure noch aus. Im Netz entstehen die ersten Webapplikationen, die in Clojure implementiert sind: „The Deadline“ [59], das bereits genannte Clojars [51] oder auch „DocuHarvest“[16] etwa sind vielversprechende Projekte.

Lebenszeit von Variablenbindungen

Lifetime-Management von Clojures Variablenbindungen, vor allem von lokalen Bindungen etwa in einem let, ist ein offener Punkt, der allerdings keine großen Veränderungen bewirken sollte. Ein ähnlicher Umfang ist zu erwarten, wenn mehr und mehr Operationen auf native Objekte der Host-Plattform zurückgreifen oder dem Entwickler Mittel an die Hand gegeben werden, dies zu erreichen. Das sollte, neben anderen Optimierungen durch den Compiler, die Performance noch einmal ein wenig verbessern.

Contrib

Beachtenswert ist auch die Spielwiese Clojure Contrib. Clojure 1.2 hat gezeigt, dass es die Perlen unter den dortigen Bibliotheken in den Lieferumfang von Clojure schaffen können. Diskutiert wurde auch bereits das Build-System von Clojure Contrib. Derzeit entsteht ein großes JAR-File, denkbar sind aber auch Builds der einzelnen Bestandteile und ein Abhängigkeitsmanagement etwa mit Maven.

Threadmanagement

Bei der Arbeit mit Threads im Allgemeinen und dem Pool der Agents im Besonderen fällt auf, dass es für Agents nur zwei Thread-Pools gibt. Es fällt nicht schwer, sich vorzustellen, dass das Management von Threads und deren Prioritäten sowie von verschiedenen Thread-Pools im Laufe der Zeit an Bedeutung gewinnen wird. Die stetige Arbeit am Prozess-Scheduler des Linux-Kernels etwa zeigt, dass dieses Thema nicht im Vorbeigehen lösbar ist. Auf einen Vorschlag von Alex Miller [47] hat Rich Hickey positiv reagiert und angedeutet, dass nach der Veröffentlichung von Clojure 1.2 in dieser Richtung etwas unternommen werden könnte.

7.3  Vorhang

Mit dem soeben erfolgten Blick in die Kristallkugel fällt der Vorhang für dieses Buch. Wir hoffen, dass wir einen leichten Einstieg, umfangreiches Alltagswissen und einige interessante Hintergründe vermitteln konnten. Die Gemeinschaft der Clojure-Entwickler und -Anwender ist ausgesprochen freundlich, und im IRC-Kanal wie auch auf der Mailingliste ist jeder herzlich willkommen.