Skip to content

Instantly share code, notes, and snippets.

@mfikes
Last active November 23, 2020 13:27
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfikes/bafa82eb52d517cb14cf6815320af41f to your computer and use it in GitHub Desktop.
Save mfikes/bafa82eb52d517cb14cf6815320af41f to your computer and use it in GitHub Desktop.

The following works in Clojure:

(keys (filter (comp odd? val) {:a 1 :b 2 :c 3}))

The docstrings for keys and vals don't indicate that you can do this. Is this accidential or intentional?

I vaguely recall Alex Miller indicating at some point that this capability was deemed useful and is intentionally allowed. Yes, this is an appeal to authority, but nevertheless, it makes a fairly convincing argument.

There was evidently an attempt to disallow this, which was reverted because it evidently breaks subseq.

There are unit tests that specifically check that you can pass various empty seqables to keys and vals and get back nil (thus arguing, indirectly via the presence unit tests, that it is intentional that these functions can accept things other than maps—perhaps so long as they are empty seqables.)

There is a comment in CLJ-1602 that touches specifically on the fact that sequences of map entries are passed to these functions

There are a few places that rely on passing a seq of Map.Entry to keys/vals (not just a map instance)...

and the relevant patch specifically takes care not to break code that relies on this behavior.

While the above isn't evidence that the capability is truly intentional and supported, this appears to be the strongest evidence that there is at least a circumspect intent not to break existing usage.

There is a Clojuredocs example specifically illustrating this use case. This is of course not evidence that such programs are valid; it only illustrates that it is a known capability.

In summary, my hunch is that it wasn't intentional, but was discovered to be useful, and is now in a place where you can rely on it working even though it isn't formally documented. Your ability to use it safely depends on the combination of Hyrum's Law at work, and the Clojure team's conservative stance, leaning towards never breaking things if at all possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment