Clojure Destructuring Gotcha!
Given the following function definition, what would you expect to happen if you ran (hello :person nil)
?
(defn hello
[& {:keys [person]
:or {person "Rich"}}]
(str "Hello, " person))
(hello) => "Hello, Rich"
(hello :person "Hickey") => "Hello, Hickey"
(hello :person nil) => "Hello, "
I’d have expected (hello :person nil)
to have the same result as calling (hello)
, but as it turns out, Clojure seems to make a distinction between nothing and nil
when it comes to destructuring.
A real world situation where this might occur would be where you, for instance, rely on the result of a destructuring operation to provide parameters for a function similar to hello
. e.g.
(defn spam
[& {:keys [person]}]
(str (hello :person person)
"Give me all your money."))
Calling (spam)
would result in (hello :person nil)
being called, which would have the – probably – unintended effect of returning "Hello, "
. You may choose to add an :or
when destructuring the argument to spam, but then you’ll have the same code appearing twice. A more localised solution would be changing the hello
definition to be something like this.
(defn hello
[& {:keys [person]}]
(str "Hello, " (or person "Rich")))
This worked for my case, but I’d love to hear about more idiomatic approaches.