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?
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