Search code examples
clojuremacros

How does clojure evaluate code at compile time?


Here are two macros I had written

(defmacro hello [x] '(+ 1 2))

&

(defmacro hello [x] (eval '(+ 1 2)))

On macroexpanding the first one, I get (+ 1 2), and while macroexpanding the second, I get the value 3. Does this mean the addition happened at compile time? How is that even possible? What if instead of '(+ 1 2) I had written a function that queries a db. Would it query the db at compile time?


Solution

  • A macro injects arbitrary code into the compiler. Usually, the purpose is to "pre-process" custom code like (1 + 2) into something Clojure understands like (+ 1 2). However, you could include anything (including DB access) into the compilation phase if you really want to. After all the compiler is just a piece of software running on a general-purpose computer. Since it is open-source, you could modify the compiler code directly to do anything.

    Using a macro is just a more convenient way of modifying/extending the base compiler code, that is optimized for extending the core Clojure language. However, macros are not limited to that use-case (if you really want to get crazy).


    There is a similar ability using the C++ expression template mechanism, which is a Turing Complete compiler pre-processor. A famous example was to use the compiler to compute the first several prime numbers as "error" messages. See http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s04.html#Static-metaprogramming