Clojure functions and gensym
I have a question about some code in the Clojure compojure library.
(defn compile-route
"Compile a route in the form (method path & body) into a function."
[method route bindings body]
`(make-route
~method ~(prepare-route route)
(fn [request#]
(let-request [~bindings request#] ~@body))))
I've only seen gensyms used in the context of macros, where they are used to avoid collisions between the bindings used in the macro and bindings in the local scope.
I would have thought that since the above is a function and not a macro, it is immune to this. So I'm wondering what the rationale is for writing this function as a macro.
(If you're interested, I checked the commit history to see if this function was originally recorded as a macro. It isn't.)
source to share
Although what you see is a function, not a macro, it is a function that generates Clojure code . (This will almost certainly be called from within a macro.) And not only generates code, but also inserts code that is passed as an argument body
into the generated code. This is why name collisions should be avoided.
While not a macro, it does the same thing as macros and uses gensym for the same reason.
source to share
Gensyms (notation -#
at least) are not used in the context of macros, but in the context of backquote. To more or less provide a macro, symbols that do not allow globally qualified symbols cannot be used within the context of a backquote. While this does not apply, and there is an escape, if you really want the unqualified character, it provides a normal default. For a longer discussion of macrohygiene in Clojure see this blog post.
source to share