Interaktivität ist bekanntlich eines der wesentlichen Merkmale von Programmierung in Lisp. Sicherlich ist das einer der Gründe dafür, daß sich das Entwickeln von GUI-Anwendungen in Lisp immer etwas unnatürlich anfühlt. Wenn man nicht gerade ein besonders lispiges Framework wie den Common Lisp Interface Manager oder ein smalltalkesques wie Morphic zur Verfügung hat — und im Falle von Clojure hat man zu meinem großen Bedauern keines von beiden — dann ist die einzige Möglichkeit, die noch bleibt, ein traditionelles GUI-Toolkit zu verwenden, das sich halbwegs interaktiv programmieren läßt.

Nun ist das mit der Interaktivität so eine Sache. Die meisten Programmiersprachen lassen sich in dieser Weise gar nicht nutzen, sondern setzen einen umständlichen Editieren-Kompilieren-Starten-Zyklus voraus. Das gilt insbesondere für die populären Sprachen mit C-artiger Syntax. So erstaunt es auch nicht, daß verbreitete Toolkits wie Gtk+ und Qt den Programmierer zwingen, Dinge zu tun, die in einem interaktiven Kontext völlig inakzeptabel wären. Eines davon ist folgendes Codemuster (hier beispielhaft für Qt-Jambi in Java, anderswo sieht es ähnlich aus):

gdk_threads_enter();  
// GUI-Code hier.  
gdk_threads_leave(); 

Code, der auf das Benutzerinterface zugreifen will, beispielsweise um es zu verändern, muß in einem Kontext stehen wie der Kommentar „GUI-Code hier“ oben im Codebeispiel. Der Grund dafür ist, daß die verbreiteten Toolkits stets nur einem einzelnen, bestimmten Thread den Zugriff auf das Interface erlauben.

Für interaktive Programmierung ist die Erzwingung dieses Codemusters katastrophal. Es ist nicht möglich, in der Clojure-REPL mal schnell einen Button zu erzeugen und ihn auf das bestehende Interface zu kleben, um auszuprobieren, wie das aussieht. Schließlich will wirklich niemand ernsthaft Dinge wie (try (threads-enter) (.show button) (finally (threads-leave))) anstelle von (.show button) eintippen wollen — jedenfalls definitiv nicht an einer Befehlszeile!

Genausowenig kann man schnell in einem geöffneten Editorfenster C-M-x drücken, um eine Label-Beschriftung zu aktualisieren, die man gerade angepaßt hat.

Vielleicht kann jemand, der interaktives Programmieren nicht gewohnt ist, nicht gleich verstehen, warum das alles ein riesiges Problem ist. Nichtsdestotrotz ist es eine Tatsache, daß sich in der Welt von Common Lisp trotz der Verfügbarkeit von Gtk+- und wxWidgets-Anbindungen immer noch Tk als Quasistandard für GUI-Programmierung hält. Ich bezweifle, daß es Zufall ist, daß gerade dasjenige Toolkit am meisten Zuspruch erhält, das das Problem des abgetrennten GUI-Threads nicht aufweist.

Lassen wir nun aber Tk einmal außen vor. Abgesehen davon, daß es, wie es scheint, keine akzeptable Java-Anbindung dafür gibt, mutet es doch zumindest unter X11-basierten Systemen etwas prähistorisch an. Was gibt es für moderne Clojure-Programmierer für Alternativen?

Da wäre freilich einmal JFC/Swing. Genügend Leute klagen über das barocke API. Doch: Entgegen jeder rationalen Erwartung, kennt Swing das Problem des GUI-Threads nicht! Es eignet sich somit ganz hervorragend zum interaktiven Zusammenbasteln von GUIs.

Nun, vielleicht nicht ganz hervorragend. Wie gesagt, ist das API barock und etwas unhandlich zum interaktiven Programmieren. Hinzu kommt, daß es keine realistische Möglichkeit gibt, zur Laufzeit ein mit einem GUI-Designer entworfenes Interface zu laden. Matisse zum Beispiel, der für Swing-Verhältnisse exzellente GUI-Designer in Netbeans, erzeugt Java-Code. Um den zur Laufzeit neu zu laden, müßte man erst die alte Instanz irgendwie aus dem Speicher kriegen, und dann— nein. Viel zu aufwendig.

Vielleicht ist Qt die Lösung? Der Qt Designer erzeugt XML-Beschreibungen des entworfenen Interfaces, die man zur Laufzeit laden kann. Doch — oh Schreck! — wie muß man GUI-Code bei Qt aufrufen?

QCoreApplication.invokeAndWait(new Runnable() {  
  public void run() {  
    // GUI-Code hier.  
  }  
} 

Nein, nein und nochmal nein! So wird das nichts mit der interaktiven Programmierung. Es sei denn, jemand würde SLIME hacken und alle interaktiven Befehle automatisch in diesen Boilerplate einpacken, bevor sie ausgeführt werden...

Gesagt, getan. Zwar schreibe ich im Moment keine GUI-Anwendungen, aber mit diesen kleinen SLIME-Hacks bewaffnet, werde ich beim nächsten Mal Qt in Erwägung ziehen, wenn ich Bedarf an Desktopgraphik habe.