Clojure Macros: Creating vars from a map

The other day I was looking for a way to turn a map into a bunch of vars. I know a macro is what will get the job done but I write macros so rarely that it always takes me a while to figure it out. In the end I ended up with something like this:

(defmacro def-all [m]
  (->> (for [[n v] m]
         `(def ~(symbol n) ~v))
       (into [])))

Using macroexpand you can see that this translates to the a bunch of def calls in a vector:

user=> (macroexpand '(def-all {:a 1 :b 2}))
[(def a 1) (def b 2)]

Like myself, you may wonder why the vector is needed. The issue is that for will return a list and that would result in the macro emitting the following Clojure code:

((def a 1) (def b 2))

After evaluating the two inner def forms, this will result in another function call where the return value of the first def is used as a function. Depending on what you are defining this may fail or lead to unexpected behavior.

After sharing my solution using (into []) in the Clojurians Slack I was made aware that instead if turning the thing into a vector you can also just prepend a do into that list, resulting in code that feels slightly more aligned with my intention:

(defmacro def-all [m]
  (->> (for [[n v] m]
         `(def ~(symbol n) ~v))
       (cons 'do)))

(macroexpand '(def-all {:a 1 :b 2}))
; returns
(do (def a 1) (def b 2))

I realize this is a super basic macro but I can totally see how that might be useful to people starting to write their own macros. If you're looking for a more full-fledged guide, Clojure for the Brave and True got you covered.

Thanks to Justin Smith for sharing his experience on Slack with me so many times.

Other Posts

  1. Promises in a ClojureScript REPLMay 2020
  2. Improved Support for Foreign Libs in cljdocMay 2020
  3. Static Blogging, Some Lessons LearnedMay 2020
  4. Working with Firebase Documents in ClojureScriptSeptember 2019
  5. 4 Small Steps Towards Awesome Clojure DocstringsJanuary 2019
  6. Sustainable Open Source: Current EffortsJanuary 2018
  7. Maven SnapshotsJune 2017
  8. Requiring Closure NamespacesMay 2017
  9. Simple Debouncing in ClojureScriptApril 2017
  10. Making Remote WorkMarch 2017
  11. Just-in-Time Script Loading With React And ClojureScriptNovember 2016
  12. Props, Children & Component Lifecycle in ReagentMay 2016
  13. Om/Next Reading ListNovember 2015
  14. Parameterizing ClojureScript BuildsAugust 2015
  15. ClojureBridge BerlinJuly 2015
  16. Managing Local and Project-wide Development Parameters in LeiningenJune 2015
  17. Formal Methods at AmazonApril 2015
  18. (lisp keymap)February 2015
  19. CLJSJS - Use Javascript Libraries in Clojurescript With EaseJanuary 2015
  20. Why Boot is Relevant For The Clojure EcosystemNovember 2014
  21. S3-Beam — Direct Upload to S3 with Clojure & ClojurescriptOctober 2014
  22. Patalyze — An Experiment Exploring Publicly Available Patent DataOctober 2014
  23. Running a Clojure Uberjar inside DockerSeptember 2014
  24. Using core.async and Transducers to upload files from the browser to S3September 2014
  25. Emacs & VimJuly 2014
  26. Heroku-like Deployment With Dokku And DigitalOceanMarch 2014
  27. Woodworking MasterclassesFebruary 2014
  28. Early Adopters And Inverted Social ProofFebruary 2014
  29. Living SmallFebruary 2014
  30. Sending You a TelegramJanuary 2014
  31. Running a Marathon, Or NotJanuary 2014
  32. Code SimplicityJanuary 2014
  33. What do we need to know?December 2013
  34. Sculley's DiseaseDecember 2013
  35. A Resurrection PostDecember 2013
  36. A Trip To The USSeptember 2013
  37. Analytics DataApril 2013
  38. Asynchronous CommunicationApril 2013
  39. From Zero to Marathon in Six MonthtsMarch 2013
  40. Git Information in Fish Shell’s PromptDecember 2012
  41. When We Build StuffAugust 2012
  42. Models, Operations, Views and EventsJuly 2012
  43. The Twelve Factor AppJune 2012
  44. Paris And BackMay 2012
  45. A Friend Is Looking For A Summer InternshipMay 2012
  46. Kandan Team ChatMay 2012
  47. Entypo Icon SetMarch 2012
  48. Startups, This Is How Design WorksMarch 2012
  49. Hosting A Static Site On Amazon S3February 2012
  50. Exim4 Fix Wrongly Decoded Mail SubjectJanuary 2012