Clojure and XNAT: Introduction

Over the last two years, I’ve been using Clojure quite a bit for managing, testing, and exploratory development in XNAT. Clojure is a new member of the Lisp family of languages that runs in the Java Virtual Machine. Two features of Clojure that I’ve found particularly useful are seamless Java interoperability and good support for interactive development.

“Interactive development” is a term that may need some explanation: With many languages — Java, C, and C++ come to mind — you write your code, compile it, and then run your program to test. Most Lisps, including Clojure, have a different model: you start the environment, write some code, test a function, make changes, and rerun
your test with the new code. Any state necessary for the test stays in memory, so each write/compile/test iteration is fast. Developing in Clojure feels a lot like running an interpreted environment like Matlab, Mathematica, or R, but Clojure is a general-purpose language that compiles to JVM bytecode, with performance comparable to plain old Java.

One problem that comes up again and again on the XNAT discussion group and in our local XNAT support is that received DICOM files land in the unassigned prearchive rather than the intended project. Usually when this happens, there’s a custom rule for project identification where the regular expression doesn’t quite match what’s in the DICOM headers. Regular expressions are a wonderfully concise way of representing text patterns, but this sentence is equally true if you replace “wonderfully concise” with “maddeningly cryptic.”

Clojure has special syntax for regular expressions, so testing them is as easy as firing up your REPL (Read-Eval-Print-Loop, Lisp jargon for the interactive environment) and trying your regular expression against some test cases:

user=> (re-seq #"PN-(\d+)" "PN_371")
nil

What did I just do?

user=> is the prompt: Clojure is telling you that it’s ready for you to type something.

re-seq is the function we’re calling. It returns a sequence of regular expression matches, or nil if it fails.

#"PN-(\d+)" is the regular expression. The # in front tells the Clojure reader that the following string should be interpreted as a regular expression. This is analagous to the Java expression:

Pattern.compile("PN-(\\d+)");

"PN_371" is the string we’re testing against the regular expression.

nil is an empty result, indicating that there was no match. Let’s modify the regular expression to try to match the value.

user=> (re-seq #"PN[-_](\d+)" "PN_371")
(["PN_371" "371"])

That’s better! Now we get a sequence (surrounded by parentheses () ) containing one array (surrounded by square brackets [] ) of match groups. As with Java’s Matcher.group(i), group 0 is the text that matched the whole pattern, and each following group is the part of the text that matched the subpattern in a parenthesis pair in the original regular expression. By default, XNAT’s DICOM receiver (and the old
XNAT 1.4 DicomServer) use group 1 for extracting project titles, but that can be changed in dicom-project.rules (or the project_spec element of DicomServer.xml).

This is a very simple example, but it shows some advantages of a JVM-based, interactive environment: we’re using the same Java pattern matching machinery that XNAT uses, but we don’t have to build all the Java class boilerplate, write code to deal with input and output, and then compile and run the class. We can test a new regular expression or string as quickly as we can type it.

There are other JVM languages with interactive environments. Before Clojure came along, I often used BeanShell for testing regular expressions (but not for much else). Many people like Groovy. Scala has a REPL too. JRuby and Jython are JVM implementations of languages you may already know. I’m a long-time parenophile, so Clojure is a natural fit for me.

I’ve skipped a lot of details, most notably how to get and run Clojure. One really easy way is to go to Try Clojure and use their REPL in your browser. The example above runs there.  I’ve heard good things about Clooj as a starting point for beginners. There are plugins for the big Java IDEs — Enclojure for Netbeans, Counterclockwise for Eclipse, La Clojure for IntelliJ — but most Clojure power users use good old Emacs with SLIME and swank-clojure. Finally, the Clojure website has lots of documentation and links to all sorts of useful resources.

This entry was posted in Clojure and XNAT. Bookmark the permalink.

3 Responses to Clojure and XNAT: Introduction

  1. I’m a long-time parenophile, so Clojure is a natural fit for me.

    I’ve looked at Clojure, but was scared off by my parenophobia.

  2. Bill,

    That’s not uncommon. I think that some of those other JVM languages could be equally good for the sorts of things I’ve been doing with Clojure, and I’d love to see someone do something similar in a less polarizing language. Maybe once I’ve had a chance to post some more interesting examples, someone will feel inspired to do it even better in Groovy.

  3. Pingback: Clojure and XNAT: Using the REST API | XNAT Blog

Leave a Reply

Your email address will not be published. Required fields are marked *

*


four * = 28

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>