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