I have the following function which gives me a hash-map:
(build-quarter-note-group 60)
;;=> {0.0 "c'", 2.0 "cisis'", -2.0 "ceses'", 0.5 "cih'", -0.5 "ceh'", 1.0 "cis'", -1.0 "ces'", 1.5 "cisih'", -1.5 "ceseh'"}
Then i get the values by get
ing the keys in the map in another function.
(defn keynum->name
([keynum] (->> 0.0 (get (build-quarter-note-group keynum))))
([keynum transposition] (->> (float transposition) (get (build-quarter-note-group keynum)))))
Since the keys are all floats in the keynum->name
function i did try to do a type coercion, but this happened:
(keynum->name 60 1) ;;=> nil
(get (build-quarter-note-group 60) (float 1)) ;;=> nil
What happens to the result of the (float 1)
?
Quoting from the answer given to the issue I opened in the Clojure Jira:
I believe that the fact that get lookup of a float in a map with at most 8 keys is an accident of the implementation.
The reason why it fails with larger maps and hash sets is that the hash value is different for (double 1.0) and (float 1.0).
user=> (hash (float 1.0))
1065353216
user=> (hash 1.0)
1072693248
All of the values like 1.0 and others in your example default to type double. Note that if you force the keys of a map to be float, then lookup succeeds, even if the map has more than 8 keys:
user=> (get {(float 1.0) "a" 2.0 "b" 3.0 "c" 4.0 "d" 5.0 "e" 6.0 "f" 7.0 "g" 8.0 "h" 1 "i"} (float 1))
"a"
My guess is that except for the accident that get with a small map happens to return a successful lookup, everything here is working as designed.
I believe the reason that get with a small map does find a match for looking up (float 1) is probably because the implementation of small maps is as an ArrayMap, where lookup keys are sequentially compared against all keys in an array using clojure.core/= (or its Java equivalent), and:
user=> (= (float 1) (double 1))
true
So, in short - the keys in your map are doubles and not floats.
(get (build-quarter-note-group 60) (double 1))
=> "cis'"