Re: Difficulty understanding (new?) behavior of identical?

2012-05-05 Thread Daniel Solano Gómez
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.

I hope this clears things up.

Sincerely,

Daniel


signature.asc
Description: Digital signature


Re: Difficulty understanding (new?) behavior of identical?

2012-05-05 Thread David Sletten

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 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

Re: Difficulty understanding (new?) behavior of identical?

2012-05-05 Thread Daniel Solano Gómez
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 

Re: Difficulty understanding (new?) behavior of identical?

2012-05-05 Thread David Sletten
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