Fork me on GitHub
#beginners
<
2023-09-26
>
Henrique Prange23:09:20

Why does a sequence of a single map behave as a regular map when destructuring? For example, I expected the code below to return nil.

(let [{:keys [values]} '({:values [1 2 3]})]
  values)
=> [1 2 3]
Is there a specific reason for this behavior?

👍 1
seancorfield23:09:08

I believe it's because of this, introduced in Clojure 1.11: https://clojure.org/news/2021/03/18/apis-serving-people-and-programs (I think it failed in 1.10).

seancorfield23:09:55

Confirmed:

> clj -A:1.10
Clojure 1.10.3
user=> (let [{:keys [values]} '({:values [1 2 3]})]
  values)
Execution error (IllegalArgumentException) at user/eval137 (REPL:1).
No value supplied for key: {:values [1 2 3]}
user=>

phronmophobic23:09:13

You can see what's happening by looking at the output of destructure

> (destructure '[{:keys [values]} '({:values [1 2 3]})])
[map__10416
 '({:values [1 2 3]})
 map__10416
 (if
  (clojure.core/seq? map__10416)
  (if
   (clojure.core/next map__10416)
   (clojure.lang.PersistentArrayMap/createAsIfByAssoc
    (clojure.core/to-array map__10416))
   (if
    (clojure.core/seq map__10416)
    (clojure.core/first map__10416)
    clojure.lang.PersistentArrayMap/EMPTY))
  map__10416)
 values
 (clojure.core/get map__10416 :values)]

phronmophobic23:09:35

I don't think I would rely on this specific behavior in let statements though.

Henrique Prange23:09:43

@U04V70XH6 @U7RJTCH6J Thanks for the information. This behavior led to some unexpected results in my unit tests, so I’ll need to include an assertion to ensure that the return value is indeed a map.

seancorfield23:09:01

(let [{:keys [values]} (when (map? data) data)]
  values)
🙂 If you were doing multi-version testing (against multiple versions of Clojure), I expect your tests would have blown up 1.10 and earlier (may not be applicable if this is an app but possibly worth doing for a library).

Henrique Prange23:09:52

Absolutely, your solution does the trick too. Nevertheless, I’m going to add a comment to clarify why this verification is necessary. Thanks once again!