Clojure Tutorial, Teil 2: Namespaces


Dies ist der zweite Artikel in einer kleinen Serie, die meine ersten Schritte in der neuen funktionalen Programmiersprache Clojure dokumentieren soll. Die Artikel werden in unregelmäßigen Abständen hier publiziert.

Im letzten Artikel habe ich in dem erweiterten Hallo Welt eine Var definiert, in der ich die auszugebende Nachricht Hallo Welt abgelegt hatte. Man könnte jetzt glauben, eine Var ist gleichbedeutend mit einer globalen Variable, aber das ist nicht so.

Namespaces

In Clojure sind alle Variablen und Funktionen “gescoped”, d.h. mit einem Gültigkeitsbereich belegt. Startet man die REPL, wird automatisch der Namespace “user” angelegt. Man kann den Namespace einfach mit der special form ns wechseln:

$ java -cp clojure.jar clojure.main
Clojure 1.3.0-alpha3-SNAPSHOT
user=> (ns mynamespace)
nil
mynamespace=>

Mit der Funktion (ns mynamespace) erstelle ich einen neuen Namespace und wechsel direkt dort hinein. Anschliessend kann ich dort Vars und Funktionen erstellen, und zwar ohne explizit den Namespace angeben zu müssen. Allerdings kann ich sie ausserhalb meines Namespaces nur voll qualifiziert referenzieren, d.h. ich muss immer den Namespace mit angeben:

mynamespace=> (def msg "Hallo Welt")
#'mynamespace/msg
mynamespace=> (println msg)
Hallo Welt
nil
mynamespace=> (ns user)
nil
user=> (println msg)
CompilerException java.lang.Exception: Unable to resolve symbol: msg in this context, compiling:(NO_SOURCE_PATH:5)
user=> (println mynamespace/msg)
Hallo Welt
nil
user=>

Ich habe die Var mynamespace/msg angelegt und anschliessend in einen anderen Namespace gewechselt. Dort habe ich versucht, die Var msg auszugeben, die im Namespace user gar nicht existiert und der Compiler hat das mit einer Fehlermeldung quittiert. Anschliessend habe ich den vollständigen Namen mynamespace/msg verwendet und konnte die Var erfolgreich ausgeben.

Organisation in Dateien

Um die Organisation der Quelltexte in Dateien zu vereinfachen, gibt es eine kleine Regel:

Jede Datei hat ihren eigenen Namespace, die erste Form in einer Datei ist die special form ns.

Wenn man allerdings in einer Datei sehr oft Funktionen eines anderen Namespace verwendet, kann man den Schreibaufwand etwas reduzieren, in dem man alle Funktionen des anderen Namespace in den eigenen importiert. Dazu verwendet man die :use Direktive der special form ns:

user=> (ns mynamespace (:use clojure.xml))
nil
mynamespace=> parse
#<xml$parse clojure.xml$parse@55a7b0bf>
mynamespace=>

Die seltsame Ausgabe ist Clojures Repräsentation der Funktion parse, das kann jetzt erstmal ignoriert werden. Der springende Punkt ist die Tatsache, dass ich die Funktion clojure/xml/parse ohne Angabe des voll qualifizierten Namen aufrufen kann. Damit werden die eigenen Quelltexte wieder etwas kürzer und hoffentlich lesbarer.

Weitere Artikel

Der letzte PR

Fahrrad geklaut

Erstes Review des Sony XZ Premium

Unterschiedliche Sichtweisen

Vorbestellt: Sony Xperia XZ Premium

Giants Run 2017

Gelesen: SciFi Serie 'The Expanse'

Neue Tastatur: Pok3r Vortex RGB

New minecraft survival mod for 1.11.2

Änderungen beim Flug mit Quadkoptern