This episode is for subscribers only. Sign Up or Log in to watch it.

12. Clojure Keyword Arguments

Published 26 July 16

Clojure’s variable argument functions combined with map destructuring results in a concise syntax for keyword arguments. We’ll pick this feature apart to see exactly what’s inside. You’ll learn about “mapply”, and learn why keyword arguments aren’t always the best solution.

Show notes

I want to zoom in for a moment on the use of keyword arguments in Clojure. Although the syntax takes some getting used to they’re a great feature to acquaint yourself with. And the best part? They don’t really exist!

To set the stage, we’ll start with a simple Hiccup component, for rendering information about a specific tea on our website.

(defn tea-info-sheet [& {:keys [name type description]}]
  [:div.tea
   [:h2.name name (if type [:em "(" [:a {:href (str "/type/" type)} type] ")"])]
   [:p.description description]])

And here’s how you would use it. The arguments are specified as key-value pairs, the way you would when creating a hash-map.

(tea-info-sheet :name "Alishan"
                :type "Wulong"
                :description "Hand picked high-mountain tea grown close to the Yushan national park.")

;;=>
[:div.tea
 [:h2.name "Alishan" [:em "(" [:a {:href "/type/Wulong"} "Wulong"] ")"]]
 [:p.description
  "Hand picked high-mountain tea grown close to the Yushan national park."]]

There’s quite some syntax in that argument list though. Let’s try to pick that apart, until we get to the bottom of it, then build it up again step by step.

The first thing you notice is that initial ampersand. Normally in an argument list this is followed by a single “rest” argument, which will receive any remaining arguments gathered up in a collection.

Errata

Destructuring a vector as a map does not work the way destructuring a list works, like the episode claims. A vector is an associative data structure, where values are associated with their index. It is possible to use map (associative) destructuring with vectors, but only based on index. For instance, this will pull out the third and sixth item out of the vector and assign them to x and y.

(let [{x 2 y 5} [10 11 12 13 14 15]]
  {:x x
   :y y})
;;=>
{:x 12, :y 15}

Mapply

Can be found in Medley, Encore, Plumbing, or simple in its own jar

(defn mapply
  [f & args]
  (apply f (apply concat (butlast args) (last args))))

Further reading