Clojure

keys and vals consistency not mentioned in docstring

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Completed
  • Affects Version/s: Release 1.5
  • Fix Version/s: Release 1.6
  • Component/s: None
  • Labels:
  • Patch:
    Code
  • Approval:
    Ok

Description

(keys m) and (vals m) appear to return stuff in a consistent order, so (= m (zipmap (keys m) (vals m))). This consistency is a useful property. The API docs should state whether it is part of the functions' contract.

Patch: clj-1302-2.patch

  1. clj-1302-2.patch
    05/Feb/14 11:25 AM
    1.0 kB
    Alex Miller
  2. clj-1302-1.patch
    05/Feb/14 12:42 AM
    1.0 kB
    Alex Miller

Activity

Hide
Gary Fredericks added a comment -

One thing to keep in mind is that the functions can be used on arbitrary instances of java.util.Map, which, aside from being mutable, could hypothetically (though not realistically) generate their entry sets nondeterministically.

I don't know what any of this means about what the docstring should say. It could claim the consistency for clojure's collections at least.

Show
Gary Fredericks added a comment - One thing to keep in mind is that the functions can be used on arbitrary instances of java.util.Map, which, aside from being mutable, could hypothetically (though not realistically) generate their entry sets nondeterministically. I don't know what any of this means about what the docstring should say. It could claim the consistency for clojure's collections at least.
Hide
Andy Fingerhut added a comment - - edited

The ticket creator might already realize this, but note that (= m (zipmap (keys m) (vals m))) is guaranteed for Clojure maps, where m is the same identical map, at least by the current implementation. I am not addressing the question whether it is part of the contract, but I think it would be good to make this explicit if it is part of the contract.

The following is not guaranteed for Clojure maps: (= m1 m2) implies that (= (keys m1) (keys m2)).

The set of keys/vals will be equal, but the order of keys/vals could be different for two otherwise equal maps m1, m2.

Show
Andy Fingerhut added a comment - - edited The ticket creator might already realize this, but note that (= m (zipmap (keys m) (vals m))) is guaranteed for Clojure maps, where m is the same identical map, at least by the current implementation. I am not addressing the question whether it is part of the contract, but I think it would be good to make this explicit if it is part of the contract. The following is not guaranteed for Clojure maps: (= m1 m2) implies that (= (keys m1) (keys m2)). The set of keys/vals will be equal, but the order of keys/vals could be different for two otherwise equal maps m1, m2.
Hide
Steve Miner added a comment -

I think you can depend on a slightly stronger contract: The order of the results from `keys` and `vals` follows the order of the results from `seq`. As with any pure function, `seq` returns consistent results across multiple calls with the same (identical?) map. The order may be arbitrary for a non-sorted map, but it should be consistent.

Some time ago, I looked for this guarantee in the documentation, but I couldn't find it explicitly stated. However, after looking at the implementation, I think it's safe to depend on this invariant.

Show
Steve Miner added a comment - I think you can depend on a slightly stronger contract: The order of the results from `keys` and `vals` follows the order of the results from `seq`. As with any pure function, `seq` returns consistent results across multiple calls with the same (identical?) map. The order may be arbitrary for a non-sorted map, but it should be consistent. Some time ago, I looked for this guarantee in the documentation, but I couldn't find it explicitly stated. However, after looking at the implementation, I think it's safe to depend on this invariant.
Hide
Stuart Halloway added a comment -

The absence of this property in the docs is correct. You should not rely on this.

Show
Stuart Halloway added a comment - The absence of this property in the docs is correct. You should not rely on this.
Hide
Nicola Mometto added a comment -

I have to say this surprises me, I was relying on this undocumented behaviour expecting it to be implicit.

I did a quick search in github and the number of (zipmap (keys m) (do-something (vals m))) is significant, even some experienced clojure developers seem to have given this property for granted (https://groups.google.com/forum/?fromgroups#!topic/clojure/s1sFVF7dAVs).

Could we at least explicitely document the absence of this property in the docs in order to avoid further confusion?

Show
Nicola Mometto added a comment - I have to say this surprises me, I was relying on this undocumented behaviour expecting it to be implicit. I did a quick search in github and the number of (zipmap (keys m) (do-something (vals m))) is significant, even some experienced clojure developers seem to have given this property for granted (https://groups.google.com/forum/?fromgroups#!topic/clojure/s1sFVF7dAVs). Could we at least explicitely document the absence of this property in the docs in order to avoid further confusion?
Hide
Peter Taoussanis added a comment -

Big surprise here too. Could someone (Stu?) possibly motivate a little why this couldn't/shouldn't be a contractual property? It seems like it has utility. Perhaps more importantly, it seems to be an intuitively reasonable assumption. That's subjective, sure, but I feel like I've seen this pattern come up quite widely.

Anecdotally, am quite sure I've made use of the assumption before (i.e. that `(keys m)` and `(vals m)` will return sequences as per pair order).

Would need to review code to see how frequently I've made the error.

To clarify: not disagreeing, just want to understand the thought that's gone in.

> Could we at least explicitely document the absence of this property in the docs in order to avoid further confusion?

That'd be a big help I think. I'd generally take an

Show
Peter Taoussanis added a comment - Big surprise here too. Could someone (Stu?) possibly motivate a little why this couldn't/shouldn't be a contractual property? It seems like it has utility. Perhaps more importantly, it seems to be an intuitively reasonable assumption. That's subjective, sure, but I feel like I've seen this pattern come up quite widely. Anecdotally, am quite sure I've made use of the assumption before (i.e. that `(keys m)` and `(vals m)` will return sequences as per pair order). Would need to review code to see how frequently I've made the error. To clarify: not disagreeing, just want to understand the thought that's gone in. > Could we at least explicitely document the absence of this property in the docs in order to avoid further confusion? That'd be a big help I think. I'd generally take an
Hide
Peter Taoussanis added a comment -

End of comment got mangled somehow.

Was just going to point out that I'm a big fan of how cautious + deliberate Clojure's design tends to be. Being hesitant to pick up needless or half-baked contractual obligations, etc. is a huge strength IMO.

Show
Peter Taoussanis added a comment - End of comment got mangled somehow. Was just going to point out that I'm a big fan of how cautious + deliberate Clojure's design tends to be. Being hesitant to pick up needless or half-baked contractual obligations, etc. is a huge strength IMO.
Hide
Rich Hickey added a comment -

keys order == vals order == seq order

Show
Rich Hickey added a comment - keys order == vals order == seq order
Hide
Alex Miller added a comment -

Tweaked doc.

Show
Alex Miller added a comment - Tweaked doc.

People

Vote (2)
Watch (4)

Dates

  • Created:
    Updated:
    Resolved: