Software Architecture

# Playing with Macros

For somebody with experience with Lisp of functional programming, all this will seem trivial. But I needed to refresh all this, so here  is the result of my small investigation of Clojure macro and how it relates to lazy evaluation and quoting. I also make a few test on the  difference between macro and functions.

First I started with a global variable, and a function that produces a side-effect (incrementing the value) and then return the value of the global variable. It is then trivial to see when stuff gets evaluated.
``` (def glob-1 10) (defn side-effect [] (do (def glob-1 (inc glob-1)) glob-1 ))```

Then to clearly see the difference between macro and function I defined these two ones:
``` (defmacro print-twice [exp] `(do (side-effect)(println ~exp)(println ~exp))) (defn print-twice-2 [exp] (do (side-effect)(println exp)(println exp)))```

Here is the result of the macro:

```(print-twice glob-1) "11 11" (print-twice (side-effect))  "13 14" ```
We clearly see how the macro expands. In the 2nd call, the  side-effect is executed 3 times as expected. We can now try the function:
``` (print-twice-2 glob-1) "14 14" (print-twice-2 (side-effect)) "16 16"```

We see that `glob-1` is evalued before being passed to the function. As a consequence, 15 is never printed! The side-effect passed as parameter in the 2nd call is evaluated once, before the actual function is run.  After these two calls, `glob-1` has a value of 17.

To have a side-effect which doesn’t hard-code the reference to `glob-1`, we can turn it into a macro that takes a variable as parameter.

`(defmacro side-effect-1 [v] `(do (def ~v (inc ~v)) ~v ) )`

The result are (of course) then similar:

```(def glob-1 20) (print-twice glob-1) "21 21" (print-twice (side-effect-1 glob-1 ))  "23 24" (print-twice-2 glob-1) "24 24" (print-twice-2 (side-effect-1 glob-1 )) "26 26"```

OK, that’s great, but quasi-quoting isn’t limited to macro. I can also do it in a function.

`(defn print-twice-3 [exp] `(do (side-effect)(println ~exp)(println ~exp)))`

The result of this function is an expression. It needs to be evaluated to produce the actual result.
``` (def glob-1 30) (eval (print-twice-3 glob-1)) "30 30" (eval (print-twice-3 (side-effect))) "32 32"```

We clearly see here again that the semantic of the parameters is not the same between macro and function. The parameter `glob-1` is evaluated before being passed to the function, and as a consequence `~exp` expands twice to a literal value of 30, not the symbol `glob-1` as in a macro, and we don’t get “31 31” as we would with the macro. The same happens for the 2nd call.

EDIT

Other links related to macro and meta-programming: