Skip to content

Instantly share code, notes, and snippets.

@cjfrisz
Last active January 1, 2016 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cjfrisz/8088647 to your computer and use it in GitHub Desktop.
Save cjfrisz/8088647 to your computer and use it in GitHub Desktop.
Macros as text-rearrangers
;; It often makes sense to think about macros as taking names as arguments.
;; This is in contrast to functions which take values as arguments.
;; Consider this macro (by a user in the #clojure IRC)
(defmacro getter [obj nm]
`((memfn ~(read-string (str "get" nm))) ~obj))
;; It takes two names, obj and nm.
;; Nothing really interesting happens to obj, so let's focus on what happens with nm:
(read-string (str "get" nm))
;; It constructs a string by appending "get" to the string representing the _name_ given by nm,
;; and then reads that string as a Clojure datum.
;; Consider this expression that uses the getter macro (taken from the same IRC user as above):
(defn mine
[pdfdoc]
(with-open [doc (PDDocument/load pdfdoc)]
(let [info (.getDocumentInformation doc)]
(getter info "Title")))) ; the name given by nm is the string "Title"
;; This macro seems to work when the _name_ given by nm is a datum, as it is above:
(macroexpand '(getter info "Title") ; the name given by nm is the string "Title"
;; -> ((clojure.core/memfn getTitle) info)
;; Things seem to go awry when the getter macro is handed a variable whose _value_ is the
;; intended datum, such as in this expression (from the IRC user's question):
(defn mine2
[pdfdoc]
(with-open [doc (PDDocument/load pdfdoc)]
(let [info (.getDocumentInformation doc)]
(doseq [wd ["Title" "Subject"]]
(do
(println "got" wd)
(getter info wd)))))) ; The name given by nm is wd
(macroexpand '(getter info wd))) ; the name given by nm is wd
;; -> ((clojure.core/memfn getwd) info)
;; It seems like the intention was to hand the _value_ of wd to getter
;; (which would have been "Title" on one iteration, then "Subject on the next"),
;; but instead getter received the _name_ of the variable, wd.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment