On May 5, 2012, at 3:06 PM, Daniel Solano Gómez wrote:
> On Sat May 5 14:53 2012, David Sletten wrote:
>> Can anyone explain this change?
>> (clojure-version) => "1.2.0"
>> (let [x 8.9] (identical? x x)) => true
>>
>> Compared to:
>> (clojure-version) => "1.4.0"
>> (let [x 8.9] (identical? x x)) => false
>
> Well, this is certainly an interesting phenomenon. What is happening
> here is part of Clojure's primitive optimisations introduced in Clojure
> 1.3.
>
> Before Clojure 1.3, the code:
>
> (let [x 8.9] (identical? x x))
>
> Roughly can be thought of expanding to something like:
>
> (let [x (Float. 8.9)] (identical? x x))
>
> Since x is an object, it is indeed identical to itself.
>
> In Clojure 1.3, the code could be thought of evaluating to something
> like:
>
> (let [x (float 8.9)] (identical? (Double. x) (Double. x)))
>
> The x remains unboxed, so that when it is passed to the function call,
> which presumably has no primitive-hinted forms, it much be boxed each
> time it is an argument, and the resulting objects are not identical.
>
> To see more of the same in action (in Clojure 1.3 and above):
>
> (let [x 127] (identical? x x)) ;=> true
> (let [x 128] (identical? x x)) ;=> false
>
> The JVM has an optimisation such that boxed versions of small integers
> get boxed to cached instances. However for integers with large enough
> magnitudes, the JVM produces new objects.
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.
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.
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 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
(let [x 1234] (identical? x x)) => false
(let [x 1234N] (identical? x x)) => true
(let [x 8.9M] (identical? x x)) => true
(let [x (Double. 8.9)] (identical? x x)) => true
(class 8.9) => java.lang.Double
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.
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.
David Sletten
--
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