Clojure

clojure.lang.PersistentArrayMap keys function doesn't preserve order when number of pairs exceeds 8

Details

Description

java -cp ~/Downloads/clojure-1.8.0.jar clojure.main

```
user=> (def one-to-eight {
:one "One"
:two "Two"
:three "Three"
:four "Four"
:five "Five"
:six "Six"
:seven "Seven"
:eight "Eight"})

user=> (def one-to-nine {
:one "One"
:two "Two"
:three "Three"
:four "Four"
:five "Five"
:six "Six"
:seven "Seven"
:eight "Eight"
:nine "Nine"})

user=> (keys one-to-eight)
(:one :two :three :four :five :six :seven :eight)

user=> (keys one-to-nine)
(:one :eight :three :five :four :nine :two :seven :six)

```

Activity

Hide
Peter Ullah added a comment -

Incidentally, first notice using using 1.10.0-alpha4. 1.8 was the first .jar I came to that didn't cause a spec related exception when attempting to run java -cp etc.

Show
Peter Ullah added a comment - Incidentally, first notice using using 1.10.0-alpha4. 1.8 was the first .jar I came to that didn't cause a spec related exception when attempting to run java -cp etc.
Hide
Alex Miller added a comment -

Clojure literal maps make no guarantees on entry order. Which map implementation is used is undefined and you should have no expectation about which one that is. (For maps >8 entries, you're seeing hash map used here instead as array maps are only efficient for small maps.) So, this is the expected behavior. If you really need to retain insertion order, you can do that by using the explicit `array-map` constructor.

user=> (def one-to-nine (array-map :one "One" :two "Two" :three "Three" :four "Four" :five "Five" :six "Six" :seven "Seven" :eight "Eight" :nine "Nine"))
#'user/one-to-nine
user=> (keys one-to-nine)
(:one :two :three :four :five :six :seven :eight :nine)

Since Clojure 1.9, Clojure has a dependency on two external jars and starting it with just -cp and the clojure jar will not work. You can find instructions on how to build an all-included local jar at https://clojure.org/guides/getting_started#_other_ways_to_run_clojure.

Show
Alex Miller added a comment - Clojure literal maps make no guarantees on entry order. Which map implementation is used is undefined and you should have no expectation about which one that is. (For maps >8 entries, you're seeing hash map used here instead as array maps are only efficient for small maps.) So, this is the expected behavior. If you really need to retain insertion order, you can do that by using the explicit `array-map` constructor.
user=> (def one-to-nine (array-map :one "One" :two "Two" :three "Three" :four "Four" :five "Five" :six "Six" :seven "Seven" :eight "Eight" :nine "Nine"))
#'user/one-to-nine
user=> (keys one-to-nine)
(:one :two :three :four :five :six :seven :eight :nine)
Since Clojure 1.9, Clojure has a dependency on two external jars and starting it with just -cp and the clojure jar will not work. You can find instructions on how to build an all-included local jar at https://clojure.org/guides/getting_started#_other_ways_to_run_clojure.
Hide
Peter Ullah added a comment -

Thank you for the explanation, Alex.

Show
Peter Ullah added a comment - Thank you for the explanation, Alex.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: