Associative destructuring with defaults and referencing the whole new map

We know that while associative destructuring, :as gives us a symbol for the incoming map, and :or the means to define default values if the keys are not there.

But how to get a reference to the whole new map?

Let me explain, let’s imagine you can do it with something called :merged-as. Then, I would be expecting the following:

(let [{:keys [a b c] :or {a 1 b 2 c 3} :as m :merged-as merged} {:b 20}]
  [m merged]) ;; [{:b 20} {:a 1 :b 20 :c 3}]

Is there something like that in Clojure?

The way folks typically do this – when they need the whole map with defaults merged in – is like this:

(let [defaults {:a 1 :b 2 :c 3}
      {:keys [a b c] :as m} (merge defaults {:b 20})]
  [a b c]) ; 1 20 3

So you make the defaults explicit, and destructure on the merged map instead of the original.

3 Likes

Yes! That works.

The not ideal part is that for functions signatures, if I need the merged reference and do it in that way, I need to add that extra let nesting.

But it is well. Most of the functions have a let anyways :smiley:

Thank you very much!

When I first got started with map destructuring, I found it very odd that the :as hash map was before the default values were added and I’ve often wished for some shorthand to do this, but I guess I just got used to the let-with-merge approach and never got around to asking for enhancement…

1 Like

I never even realized that :as didn’t include the other stuff.

I think the thought process must have been that :as refers to the original input, and they’d expect you to use the bound symbols inside the function for the rest.

It could make for a good clj-kondo linter, that warns if you’re getting an :or key from the :as map.

Edit: Reported Warn on use of :or key from :as map in destructuring. · Issue #1324 · clj-kondo/clj-kondo · GitHub and Error on use of :or combined with :as for which there are no other destructuring · Issue #1325 · clj-kondo/clj-kondo · GitHub

2 Likes