Lately I was wondering how to set variables in a specific order in a :or clause in Clojure’s destructuring mini language. I needed to set a key b to the return value of a function f that is dependant on a key a .

My first thought was that the :or {} syntax wouldn’t obey the order (since it is a map), so I’ve used :or [] . But that doesn’t work at all, it does not do anything, both get bound to nil , as if no :or was specified.

When using :or {} it magically worked, but how can you trust that the order is always correct, since maps are inherently unordered?

Turns out, the order in which keys are taken from the :or map depends on the :keys vector! Compare specifying a before b , which works as expected:

1 2 3 4 5 6 7 8 9 10 11 12 13 ( destructure ' [{ :keys [ a b ] :or { a x b ( f a )}} x ]) ;=> [ map__39123 x map__39123 ( if ( clojure.core/seq? map__39123 ) ( clojure.lang.PersistentHashMap/create ( clojure.core/seq map__39123 )) map__39123 ) a ( clojure.core/get map__39123 :a x ) b ( clojure.core/get map__39123 :b ( f a ))]

with specifying b before a which fails since a is not yet known.

1 2 3 4 5 6 7 8 9 10 11 12 13 ( destructure ' [{ :keys [ b a ] :or { a x b ( f a )}} x ]) ;=> [ map__39117 x map__39117 ( if ( clojure.core/seq? map__39117 ) ( clojure.lang.PersistentHashMap/create ( clojure.core/seq map__39117 )) map__39117 ) b ( clojure.core/get map__39117 :b ( f a )) a ( clojure.core/get map__39117 :a x )]

This behaviour works well but it was rather unexpected. It kinda does explain why the :keys takes a vector as a value and not a set, because the order is important.

Thanks to Jan Stępień for getting to the bottom of this.