Clojure ist ein vollständig mit der JVM integrierter, funktionaler Lispdialekt mit einem besonderem Fokus auf Nebenläufigkeit.

Man spürt, daß der Designer der Sprache, Rich Hickey, Ahnung von Lisp, insbesondere Common Lisp, hat. Dennoch, oder vielleicht gerade deshalb (wofür sonst eine neue Sprache?) geht Clojure vom Konzept her völlig andere Wege als Common Lisp, und der Programmierstil in den beiden Sprachen ist kaum miteinander zu vergleichen.

Clojure ist interaktiv. Es hat Unterstützung für SLIME, ein großer Pluspunkt, wenn es nach mir geht. Für ein Nicht-Common-Lisp ist das ziemlich ungewöhnlich. Überhaupt ist die Mischung aus dynamischen und statisch-funktionalen Aspekten verblüffend. Einerseits bietet Clojure echte, threadgebundene dynamische Variablen, andererseits sind alle lexikalischen Bindungen unveränderlich wie in ML-artigen Sprachen. Funktionsbindungen sind dynamisch (nicht global lexikalisch wie in anderen Lisps!) und können jederzeit um- oder neu gebunden werden. Die Sprache ist dynamisch typisiert, erlaubt aber optionale Typangaben; mehr noch: Beliebige Metadaten lassen sich mit Daten und damit auch mit Code verknüpfen, auf die Makros und der Compiler ebenso wie Anwendungscode zugreifen können.

Makros sind einfache prozedurale, DEFMACRO-artige. Zugleich trennt Clojure Funktions- und Variablennamen nicht. Irgendwie soll der kuriose, nicht internierende, nebenwirkungsfreie Leser das Problem der Unhygiene, die durch die Kombination von Lisp-1 mit prozeduralen Makros auftreten kann, umgehen. Damit muß ich mich bei Gelegenheit beschäftigen.

Die Integration mit der JVM ist so vollständig, wie man sich nur wünschen kann. Jede Clojure-Datenstruktur ist eine Instanz einer Klasse mit Methoden, die man auch von Java aus sinnvoll aufrufen kann. Umgekehrt fühlen sich Java-Objekte in Clojure-Code genauso wohl. Clojure kann fröhlich alle Methoden aufrufen und die normalen Java-Collections mit den eingebauten Funktionen für Folgen verarbeiten. nth zum Beispiel funktioniert für alles, was aufzählbar ist.

Und dann ist da noch die Unterstützung für Streams, als wären sie normale Listen oder Vektoren. Folgende Definition funktioniert und liefert die unendliche Folge aller Fibonaccizahlen:

(def fibs (lazy-cat [0 1] (map + fibs (drop 1 fibs))))  
 

(take 10 fibs) liefert nach dieser Definition die ersten 10 Fibonaccizahlen. Sieht aus wie Haskell, nicht? Und das, obwohl Clojure eine streng ausgewertete Sprache ist. Wie eigentümlich!

Die Unterstützung für Nebenläufigkeit basiert lose auf einer Variation des Aktormodells und Software Transactional Memory, eine Kombination, von der ich schon länger denke, daß sie extrem sinnvoll ist. Wer sich dafür interessiert, könnte den Vortrag von Rich Hickey darüber interessant finden.

Zuguterletzt dasjenige Detail, das mir beim ersten Ausprobieren einer neuen Sprache immer gleich auffällt:

user> (/ 10 6)  
 
5/3  
 

Korrekte Arithmetik mit Brüchen und ohne Überläufe! Der Tag ist gerettet.

Alles in allem bin ich von Clojure beeindruckt. Endlich ein neuer Lispdialekt, der Zukunft haben könnte!