=> (def x [1 2])
=> (def z (hash-set [1 2]))
=> (contains? z x)
true
=> (contains? z [1 2])
true
=> (== x [1 2])
false
That means the check for contains isnt identity, but rather the same
type and same value.
You could put those three things in some kind of order of strictness :
== : the same thing
contains? : has something of the same type and value
= : the same value
im sure someone else can explain in more exact terms what happens :)
Im just starting with clojure but to me it looks right.
In the first case the compare is true because its comparing them by
value, whereas in all the other cases it fails because you are asking
if a structure with a vector in it contains a list, which isnt true
because its not comparing them by value but by identity.
thats how i would understand it.
So if you change 1 to :
(== [1 2] '(1 2))
then you get false for that as well.
Im just starting with clojure but to me it looks right.
Thanks for your posts. I think I understand what happens now, but I
still maintain that it's a bug. In particular, the Java API says: "If
two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce
the same integer result." This contract is clearly violated by
the .hashCode and .equals methods for Clojure vectors and lists:
user> (.equals [1 2] '(1 2))
true
user> (list (.hashCode [1 2]) (.hashCode '(1 2)))
(994 -1919631597)
Cheers, Jason
Am 03.01.2009 um 11:40 schrieb Martin Wood-Mitrovski:
> => (== x [1 2])
> false
== is for numbers.
1:2 user=> (def x [1 2])
#'user/x
1:3 user=> (= x [1 2])
true
The checks for = are by value not identity. Identity
can be checked with identical?, but this is rarely
needed.
Sincerely
Meikel
Neither == nor hashes require true identity.
(def v1 [1 2])
(def v2 [1 2])
(def l1 '(1 2))
(def l2 '(1 2))
You can do what I believe are simple pointer comparisons (Java ==)
with 'identical?':
(identical? v1 v1) ==> true
(identical? l1 l1) ==> true
(identical? v1 v2) ==> false
(identical? l1 l2) ==> false
If hashes used identity, then you wouldn't be able to use v1 to look
up a hash with a key of v2, but you can:
(get (hash-map v1 :found) v2) ==> :found
(get (hash-map l1 :found) l2) ==> :found
But as noted originally, hashes are a bit more strict than Clojure =:
(= v1 l1) ==> true
(get (hash-map v1 :found) l1) ==> nil
You can see why by calling the 'hash' function directly:
(hash v1) ==> 994
(hash l1) ==> -1919631597
The same applies for hash-sets. ...but not for array-maps or
sorted-maps. Others have already explained the sorted-map exception,
but it may be worth noting again as the original post demonstrated
that array-maps appear to use =, ignoring the results of 'hash'
(get (array-map v1 :found) l1) ==> :found
So you can list things that relate to equality in order from most- to
least-strict as: identical?, hash, =
The == function doesn't fit on the scale because for numbers
it seems to act like =, but for non-numbers it just returns false:
(== v1 v1) ==> false
(identical? 1 1.0) ==> false
(identical? 1 1M) ==> false
(== 1 1M 1.0) ==> true
(= 1 1M 1.0) ==> true
The value of == is that it's much faster than =, and responds well to
working with primitive numbers:
(time (dotimes [_ 123456789] (= 1 1.0))) ==> 1350.525414 msecs
(time (dotimes [_ 123456789] (== 1 1.0))) ==> 18.603425 msecs
(time (dotimes [_ 123456789] (== (int 1) (float 1.0)))) ==> 10.348273 msecs
--Chouser
== is for numbers.
Yes. Using == instead of = when the arguments are guaranteed to be
numbers can give you quite a bit of a performance boots if your loops
are tight (according to a blog post I read the other day :p )
> --Steve
But as noted originally, hashes are a bit more strict than Clojure =:
(= v1 l1) ==> true
(get (hash-map v1 :found) l1) ==> nil
The value of == is that it's much faster than =, and responds well toworking with primitive numbers:
(time (dotimes [_ 123456789] (= 1 1.0))) ==> 1350.525414 msecs
(time (dotimes [_ 123456789] (== 1 1.0))) ==> 18.603425 msecs
(time (dotimes [_ 123456789] (== (int 1) (float 1.0)))) ==> 10.348273 msecs