I've tried this with both 1.7.0 and 1.8.0 and it appears that Clojure does not destructure maps using :keys whose keys are fully qualified. I don't think it has to do with being in the tail on the arguments as it doesn't work when I switch around the function argument positions as well.
(ns foo.sandbox)
(def foo ::foo)
(def bar ::bar)
(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:foo.sandbox/foo 1, :foo.sandbox/bar 2} and foo nil bar nil
However; this works:
(defn normalize-vals
[mmap & [{a foo b bar :as ops}]]
(println "normalize-vals " ops " and foo " a " bar" b))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:cmt.sandbox/foo 1, :cmt.sandbox/bar 2} and foo 1 bar 2
Is this a defect?
You are destructuring using unqualified keywords, so instead of:
[mmap & [{:keys [foo bar] :as ops}]]
you should use
[mmap & [{:keys [::foo ::bar] :as ops}]]
You can use clojure.walk/macroexpand-all to expand normalize-vals:
(clojure.walk/macroexpand-all '(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar)))
=> (def normalize-vals (fn* ([mmap & p__26720] (let* [vec__26721 p__26720 map__26722 (clojure.core/nth vec__26721 0 nil) map__26722 (if (clojure.core/seq? map__26722) (. clojure.lang.PersistentHashMap create (clojure.core/seq map__26722)) map__26722) ops map__26722 foo (clojure.core/get map__26722 :foo) bar (clojure.core/get map__26722 :bar)] (println "normalize-vals " ops " and foo " foo " bar" bar)))))
The important part of the expansion to note is:
foo (clojure.core/get map__26722 :foo)
bar (clojure.core/get map__26722 :bar)
The keys in the map destructuring are therefore converted to keywords at compile time and the values from the foo and bar vars in the namespace will not be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With