Writing a Spring MVC macro in Clojure (part 1)

In a previous post I wrote how to write Spring MVC Controllers in Clojure. The result worked, but contained a lot of boilerplate code. Boilerplate code may be an essential part of a Java program, but in Clojure it certainly isn’t. In fact, because of Lisp’s powerful macro system, in Clojure we can eliminate boilerplate code completely! How? Let’s find out, by writing a macro for creating a Spring MVC controller class.

Macros: a very short introduction

In Lisp, there is no fundamental distinction between data structures and programs. Programs work on data structures. Programs create data structures, read data structures and manipulate data structure. But a Lisp program in itself is also a data structure. Consider the following program:

(* (+ 1 1) 2)

The program is a list (or a Lisp form) with three elements. The first element, *, is the operator. The other elements are parameters to the operator. The second element is another list, that can be decomposed the same way.

Since a program is a list, we can use normal list operators to manipulate it. The following expression replaces the 2 by a 3 in the above expression.

(replace {2 3} '(* (+ 1 1) 2))

Why is this so powerful? In Lisp, like any other programming language, you can write a function that operates on data structures. But since in Lisp programs are also data structures, you can manipulate Lisp code in exactly the same way as data. This makes it possible to extend the language, in ways you’d never thought were possible. In Java, you had to wait for years until they finally built in an extended for loop. In Lisp? You’d have extended the language yourself with just a few lines of code. How? You’d have written a macro.

A macro is like a function, but different. A function returns a value. A macro returns a piece of executable code, that is then evaluated.

The parameters to a function are first evaluated and then passed to the function. The parameters to a macro are first passed to the macro. The macro manipulates the parameters and transforms them into (another) piece of executable code. The return value of the macro is evaluated by Lisp.

Macro evaluation goes in two steps:

  1. Macro expansion: the macro is executed and returns a piece of Lisp program
  2. Evaluation: the piece of Lisp program returned by the macro is interpreted by the compiler and executed

Generating the class

Let’s start with generating an empty subclass of the Spring AbstractUrlHandlerMapping. The macro extension will exist of a (gen-class) command, that generates a class at compile time. The name of the class will be a parameter to the macro. We will write the macro in such a way that

(defmapping com.my.Mapping)

defines an (empty) subclass com.my.Mapping of AbstractUrlHandlerMapping.

The basic steps for writing a macro are easy:

  1. Backquote ` the code template you want to generate.
  2. Escape ~ the macro parameters in the code template.
  3. Write code that performs the actual transformations on the code (this is the tough part!)

Let’s apply the first two steps.

(defmacro defmapping [name]
  `(gen-class
    :name ~name
    :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping))

(defmapping com.my.Mapping)

(defn -main []
  (println (com.my.Mapping.)))

The backquoted (`) code is returned literally by the macro. Except the ~name. The ~ character tells Clojure that name, unless the rest of the code, should actually be evaluated when generating the macro expansion. To see the result of the macro expansion, type (macroexpand ‘(defmapping com.my.Mapping)) at the REPL.

Adding post-init

Now, let’s make the class actually do something when it’s constructed. We want the macro to return two Lisp forms:

  1. A definition of the -post-init function, and
  2. the above form, that defines the class and refers to the post-init function

However, a macro, like a function, can only return one form. Therefore, we have to wrap the two forms in a (do).

The naive approach would be just to add the post-init method:

(defmacro defmapping [name]
  `(do
    (defn -post-init [this]
      (println "in init"))
    (gen-class
      :name ~name
      :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
      :post-init post-init)))

However, when we compile this, it yields a “Can’t refer to qualified var that doesn’t exist”. What is happening?

Macros in Common Lisp are vulnerable for a mistake called variable capture. Suppose that you wrote a macro that expands to code that uses a variable foo. Suppose that someone else uses the macro within a piece of code, that also uses the variable foo. When the macro is expanded, the piece of code and the macro expansion may interoperate in unintended ways. This is a dangerous and common mistake in Common Lisp.

Clojure protects you from this error. Each symbol you use in a Clojure macro must refer to an existing, qualified name. Otherwise, you’ll get errors like “Can’t intern namespace-qualified symbol” or the error above.

Luckily, the solution is easy. To make sure that variable capture doesn’t occur, you have to let Clojure generate the symbol names for you. You can do this in two ways:

  • Extend the name in your macro code with #. Clojure will generate a unique name, that won’t collide with names in code that’s using the macro. In our example, we will use this# instead of this.
  • Use an explicit (gensym) command. (gensym) generates a new unique symbol for you, that you can assign to a variable and use in your macro. Because we need the post-init symbol in two different occurrences (-post-init and post-init), we will use this approach for
    post-init.

Our code now becomes:

(defmacro defmapping [name]
  (let [post-init (gensym)]
    `(do
       (defn ~(symbol (str "-" post-init)) [this#]
         (println "in init"))
       (gen-class
         :name ~name
         :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
         :post-init ~post-init
         ))))

Note the following things:

  • The first command, (let [post-init (gensym)] is NOT within the back quote. Therefore, this code is actually evaluated at macro expansion time. The command defines a variable binding post-init, that exists at macro expansion time only.
  • (str “-” post-init) builds a string that prefixes the generated name for the post-init method with a minus. (symbol) translates the string back into a Clojure symbol that can be used within a (defn). Because it is the RESULT of this expression that must be inserted in the macro expansion, and not the expression itself, we escape it with a ~.
  • Just like ~name, we also prefix ~post-init. We do not want the literal value “post-init” as the name of our post-init method, but the value of the post-init variable.
  • All other code within the back quote is returned by the macro literally, and evaluated after returning from the macro.

What’s next?

We created a macro that generates a subclass of AbstractUrlHandlerMapping with a parameterisable name. I explained why macros are so powerful. And I showed you the basic concepts how you create a macro.

The macro itself doesn’t do much yet. In a next post, we’ll add functionality to the class. I’ll show you how you can easily eliminate all the boiler plate code, by just specifying it once and forever in a single macro.

Advertisements

Tags: , , , ,

One Response to “Writing a Spring MVC macro in Clojure (part 1)”

  1. Writing a Spring MVC macro in Clojure (part 2) « Groovy Guts and Clojure Cuts Says:

    […] Groovy Guts and Clojure Cuts Adventures in Clojure and Groovy « Writing a Spring MVC macro in Clojure (part 1) […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: