On Mon, Mar 30, 2009 at 8:21 AM, Konrad Hinsen <konrad.hin...@laposte.net> wrote: > > On Mar 30, 2009, at 12:36, Mark Engelberg wrote: > >> I'm aware that a and 123 have different types, but I was under the >> impression that the hash set implementation was supposed to just rely >> on hash codes and equality. Why does the type come into play, and is >> this really the desired behavior? > > It looks like a bug to me, for the reasons you mention. > > BTW, hash sets are implemented in terms of hash maps, which show the > same behaviour: > > (def a (BigInteger. "123")) > ({a :found} 123) > > returns nil. > > Looking at the implementation of PersistentHashMap, I note that the > ultimate key equality test is (line 560): > > public LeafNode find(int hash, Object key){ > if(hash == this.hash && Util.equals(key, this.key)) > return this; > return null; > } > > The test applied is Util.equals, so let's try that: > > (. clojure.lang.Util equals a 123) > > This returns false, unlike > > (. clojure.lang.Util equiv a 123) > > which returns true. clojure.core/= calls equiv, which is why (= a > 123) is true. equiv is the same as equals EXCEPT for numbers and > Clojure collections, so perhaps sets and maps also have some surprise > behaviour for collections. > > I don't know if there is a good reason for using equals rather than > equiv in testing for key equality in maps. Using equiv would better > agree with my expectations. >
Well, the community simply has to get together on what they want here, variously: - Clojure sets and maps should implement java.util.Set and Map - Clojure Numbers are the same Integer/Float/Long/Double as Java's, and math works with Java's Numbers. - (= 1 1.0) -> true This latter 'feature' is a bear to maintain, as (.equals 1 1.0) -> false In order to satisfy the requirements of Set and Map, hash sets and maps must compare their keys using .equals, otherwise: (= (hash-set 1 2.0 3) (java.util.HashSet. [1 2 3])) -> true (= (java.util.HashSet. [1 2 3]) (hash-set 1 2.0 3)) ->false I don't own the Integer/Long/Float/Double types, and can't broaden their notion of equality - the type test is built in. It would be a lot easier and more consistent if (= 1 1.0) -> false, but that also implies (= 1 (long 1)) -> false, and people complained when that was the case. clojure.lang.Numbers should be pretty good about reducing during math ops, but you still can get Long 1 from a Java source. If people were willing to accept type-matching = for numbers, all the special casing for Numbers and collections would go away. So, the compromise is that hash map/set keys must be of a consistent type for any particular value. Rich --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---