Fantastic Daniel. Your thorough analysis has cleared up my confusion. I see now
that Java is partly to blame for this idiosyncratic behavior.
Furthermore, I agree that this is a relatively unlikely use of 'identical?'.
Considering all of the usual concerns when comparing floating-point numbers,
this is probably not worth getting worked up about.
Thanks,
David Sletten
On May 5, 2012, at 5:14 PM, Daniel Solano Gómez wrote:
> On Sat May 5 16:43 2012, David Sletten wrote:
>> Thanks for your response Daniel. You explain WHAT is apparently
>> happening here. However, I am still struggling to understand WHY this
>> is the new behavior.
>
> Yes, this is indeed a valid question. I think the answer is that this
> particular behaviour is an unintended side effect of the performance
> optimizations introduced in Clojure 1.3. By refusing to box numeric
> primitives until it's absolutely necessary, the results are generally
> much better performance for arithmetic code.
>
>> The documentation for 'identical?' states: Tests if 2 arguments are
>> the same object. To me, (identical? x x) asks whether 2 references to
>> the same object (the referent of x) are identical. Clojure 1.4's
>> response suggests that in some cases, within a given scope, a local
>> can refer to 2 different things. To be charitable, this is a
>> counterintuitive result. It's obvious that (identical? (Double. x)
>> (Double. x)) should return false, but that's not what I'm asking. To
>> suggest that x is not identical to x (within the same scope where they
>> refer to the same thing) violates one of the most fundamental laws of
>> logic.
>
> Well, arguably, this is part of the unfortunate fallout of the JVM's
> disjoint type system between objects and primitives. The key thing to
> realise is that before Clojure 1.3, (let [x 2] …) resulted in x
> referring to an object that contains the value of 2. In Clojure 1.3 and
> newer, the x in (let [x 2] …) now refers to a primitive long with the
> value 2.
>
>> You give interpretations of what is happening under the covers in both
>> pre- and post-1.3 Clojure above. Your explanation appears to
>> correspond to the observed behavior, but how did you come to this
>> realization? Can you point me to where this issue is documented? I
>> don't find any clues in the Clojure literature.
>
> I don't think it's documented, not as such. I just happen to be
> familiar with a lot of implementation details.
>
>> I see the following example in _The Joy Of Clojure_ (pg. 71):
>> (let [x 'goat y x] (identical? x y)) => true
>>
>> As you point out, this is also the behavior with cached integers (-128
>> <= n < 127). However, the following does not make the issue any
>> clearer:
>> (let [x 123] (identical? x x)) => true
>
> As we have established, the JVM's cache kicks in for this.
>
>> (let [x 1234] (identical? x x)) => false
>
> This is outside the range of the cache, the boxed values of x are
> different.
>
>> (let [x 1234N] (identical? x x)) => true
>
> Here, you are explicitly creating a clojure.lang.BigInt, an object.
>>
>> (let [x 8.9M] (identical? x x)) => true
>> (let [x (Double. 8.9)] (identical? x x)) => true
>> (class 8.9) => java.lang.Double
>
> Again for these, you are explicitly creating objects.
>
>> Furthermore, in _Clojure Programming_ (pg. 433) the authors write:
>> [identical?] corresponds directly to == in Java. This is clearly not
>> true in the example I presented. This code will print 'true' in all 4
>> cases:
>> Double d1 = 8.9;
>> Double d2 = d1;
>>
>> double d3 = 8.9;
>> double d4 = d3;
>>
>> System.out.println(d1 == d1);
>> System.out.println(d1 == d2);
>> System.out.println(d3 == d3);
>> System.out.println(d3 == d4);
>>
>> Of course, looking at the source for 'identical?' vindicates what these
>> authors have written:
>> (defn identical? [x y]
>> (clojure.lang.Util/identical x y))
>>
>> In clojure.lang.Util:
>> static public boolean identical(Object k1, Object k2){
>> return k1 == k2;
>> }
>>
>> So apparently as far as Java is concerned, my example should return
>> 'true'. Therefore something must be occurring in the reader that
>> results in the explanation which you gave.
>
> Not quite, you get the same behaviour in Java if you have to autobox the
> values like Clojure does:
>
> public class Equals {
> static boolean eq(Object lhs, Object rhs) {
> return lhs == rhs;
> }
>
> public static void main(String[] args) {
> // prints true
> System.out.println(eq(1, 1));
>
> // prints true
> System.out.println(eq(127, 127));
>
> // prints false
> System.out.println(eq(128, 128));
> }
> }
>
>
>> To be fair, the Common Lisp standard seems goofy to me on this issue
>> too. The analogous operator is EQ, documented here:
>> http://www.lispworks.com/documentation/HyperSpec/Body/f_eq.htm
>>
>> Of note is the example below:
>> (let ((x 5)) (eq x x))
>> => true
>> OR=> false
>> This states that a conforming system may return either a true or a
>> false value in this case. This doesn't make any more sense to me than
>> what Clojure is doing, but all of the Common Lisp implementations I've
>> tested (Allegro, Clozure, SBCL, CLISP) do return T as I expected.
>
> So, in the end, the question is: is this a bug? I can't speak for the
> rest of Clojure/dev on this, but I am guessing that it might not be
> considered a bug. To be fair, it would be nice if your sample code
> returned the intuitive answer. However, I think the main argument
> against it being considered a bug would be that it doesn't make sense to
> compare numbers for identity, just use =.
>
> With numbers, if you use =, the compiler will actually use a fast
> primitive equality test and sidestep any boxing, resulting in better
> performance.
>
> At least in my experience, it is relatively rare to actually use
> identical? unless I really, truly care about object identity.
>
> I hope this helps clarify the issue.
>
> Sincerely,
>
> Daniel
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en