I have a macro that produces a function. I understand that the best practice is to use gensyms to ensure naming conflicts don't happen. So I'm wondering if I need to follow this principle for the parameter names of the function the macro will define?
Here's my macro for reference:
(defmacro defroute
[routename uri meths handler]
`(defn ~routename
[~'req]
(let [req-meth# (:request-method ~'req)
bad-meth# (nil? (some #(= req-meth# %) ~meths))
any-meth# (= ~meths [:any])]
(if (:uri ~'req)
(if (and (route-matches ~uri ~'req) (and bad-meth# (not any-meth#)))
(method-not-allowed req-meth# (get-allowed ~meths))
(let [params# (route-matches ~uri ~'req)]
(if (nil? params#)
~'req
(~handler (assoc ~'req :route-params params#)))))
~'req))))
As you can see, I'm not using a gensym currently for the req parameter. I had originally and then wondered if it was necessary. Anyway, thanks for reading.
In this context the use of req is relatively safe because it establishes a local scope. As a function parameter, it will shadow any existing bindings to the symbol req in the calling namespace without damaging them. The cost of this is that if anyone tried to use the name req for any of the other parameters, such as handler, they could be in for a bit of a surprise. This code is not wrong in my view, though it does volate the principle of least supprise in some contexts. I don't see any reason not to use an auto-gensym for req considering it's only the work of adding a couple #s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With