Welcome! Please see the About page for a little more info on how this works.

+1 vote
ago in Clojure by
retagged ago by
(let [{:keys!   [card]
       :missing m} {}]
  [card m])
;; => [nil {:card nil}]

(let [{:req!    {{:as c} :card}
       :missing m} {}]
  [c m])
;; => [#object[java.lang.Object 0x...] nil]

The input has no :card, but :card is required. Expected [nil {:card nil}], as for :keys!.

Instead:
1. m is nil, so the missing key is not reported.
2. c is bound to an internal "not found" object that should not leave Clojure's code.
3. :select returns data that was never in the input:

    (def select-card
      (selector {:req!    {{:keys [a]} :card}
                 :missing m
                 :select  s}))

    (select-card {})
    ;; => {:select {:card {}}}

With a more usual nested form, the object is hidden and the bug is silent:

(let [{:req!    {{:keys [number]} :card}
       :missing m} {}]
  [number m])
;; => [nil nil]

number is nil and looks normal, but :card is still not reported as missing.

It looks like for a simple name the not-found marker is checked, recorded as missing, and replaced with nil.
For a nested form that check is skipped, and the marker is passed into the nested form.

Without :missing, it throws Missing required key: :card, as expected.

Reproduced on Clojure 1.13.0-alpha10.

1 Answer

0 votes
ago by

Good catch, thanks! Logged as https://clojure.atlassian.net/browse/CLJ-2990

...