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
-~----------~----~----~----~------~----~------~--~---

Reply via email to