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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
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