Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hygienic macros: function parameter names?

Tags:

macros

clojure

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.

like image 407
maxcountryman Avatar asked Nov 25 '25 07:11

maxcountryman


1 Answers

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.

like image 90
Arthur Ulfeldt Avatar answered Nov 27 '25 23:11

Arthur Ulfeldt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!