Is identity expected to return something other than its argument?

Here is an example where calling identity changes the return value, which, it seems to me, indicates that docstring "Returns its argument." not quite right:

 (let [x Double/NaN] (identical? xx)) ;=> false (let [x (identity Double/NaN)] (identical? xx)) ;=> true 

Is this expected? Or is it an error with the identity function somehow?

+5
source share
3 answers

It seems you found an edge related to identity , identical? and primitive vs object equality. Note that in Java, java.lang.Double / NaN is a primitive:

 public static final double NaN 

But identical compares Java objects:

 ; clojure.core (defn identical? "Tests if 2 arguments are the same object" {:inline (fn [xy] `(. clojure.lang.Util identical ~x ~y)) :inline-arities #{2} :added "1.0"} ([xy] (clojure.lang.Util/identical xy))) // clojure/lang/Util.java static public boolean identical(Object k1, Object k2){ return k1 == k2; } 

Try this trick to force NaN into a Double object instead of the unboxed primitive:

 tupelo.core=> (let [x (Double. Double/NaN)] (spyxx x) (identical? xx)) x => java.lang.Double->NaN true 

I suspect that autoboxing of primitive NaN, which may / may not occur in different use cases, is the reason for the differences you see.

+8
source

To add a little Alan's answer to boxing:

You might want to learn the == function, which is implemented as follows:

 public boolean equiv(Number x, Number y){ return x.doubleValue() == y.doubleValue(); } 

Performs a primitive comparison of two actual double s. Your example: == :

 (let [x (identity Double/NaN)] (== xx)) => false (let [x (identity Double/POSITIVE_INFINITY)] (== xx)) => true 

What's happening? Why is NaN == NaN false? Well, a primitive comparison using == should actually return false for NaN . This is strangely stated in IEEE 754 , and Java behaves this way. This is the only "number", which in comparison with itself is not equal to itself.

As an aside, to see how object equality can be weird in Java, see this:

 (identical? 127 127) => true (identical? 128 128) => false 

This is because java caches the first 2 ^ 8 unsigned ints, so compared 127 is the same object in the first example, but 128 in the second example are different objects. So, there are some errors that you need to know about with equality checking!

But the main conclusion is: identity works as it should! Just be careful when comparing things, because the concept of "equality" is not so straightforward!

+3
source

Does identity return an "argument"?

It depends on your argument.

  • If this is an expressed expression in the form of a function call, then not always.
  • If this is what the function body sees on the stack upon entry, then yes, it is.

The anomaly is due to the way Clojure functions are called.

  • Clojure functions are objects that conform to the IFn interface .
  • The call to the Clojure function translates into one of the many invoke methods - overloaded for arity - the functional object.
  • All invoke methods have Object parameters.

The result of all this is that each call to the Clojure function translates each of its arguments into some kind of Object - an identification operation, with the exception of primitives that are wrapped in the corresponding Java class: long to long , etc.

Thus, even the identity function, essentially (defn identity [x] x) , does not return a primitive argument. This cannot be, because he never sees it.


For example, consider the expression

 (inc 3) 

The number 3 is certainly long . What type (inc 3) ? Let me ask Clojure:

 (type (inc 3)) => java.lang.Long 

... a boxed long object.

Take, we are sure that 3 is a primitive long ?:

 (type 3) => java.lang.Long 

Aaaaaaagh! He is also in the box!

Not necessarily ! You cannot say, because by the time the type body sees 3 , it is put into a box, regardless of whether it was for the reader / compiler. Clojure documentation is silent. He simply says that numeric literals are usually represented as Java.

So, in general, this is an evaluation mechanism, not a specific function (for example, identity ), which is responsible for the primitive arguments of the box . This is auto boxing.

As your example shows, primitives are stored as such, without a box, at least in let forms:

 (let [x 1.0] (identical? xx)) ;=> false (let [x (identity 1.0)] (identical? xx)) ;=> true 

The fact that identical? able to distinguish between two boxes 1.0 , shows that it is held as a primitive double . (I used a regular double to show that the behavior has nothing to do with the special Double/NaN value).

Now try putting the number in var:

 (def x 1.0) (identical? xx) ;=> true (let [x (identity x)] (identical? xx)) ;=> true 

He is in the box.

While we are here, auto-boxing is idempotent:

 (identical? x (identity x)) ;=> true 

The above does not add much to the fact that Alan Thompson and Josh’s answers and comments by Alan Mallow and Lee. I just felt that they hooked and played the fish without planting it.

0
source

Source: https://habr.com/ru/post/1269267/


All Articles