In clojure, is (= 'a 'a) referring to the 'same atom'?
In some implementations of Common LISP we can say that for the following expression
(eq 'a 'a)
Is true
because 'a
and 'a
are the "same atom".
This may be implementation dependent, but it seems the phrase (used in a popular LISP teaching book) assumes that atoms of the same value are stored in the same location in memory.
In Java, two interned strings of the same value are stored in the same location in memory.
Now Clojure on the JVM inherits Java's legacy, but is it true to say开发者_StackOverflow中文版 that two atoms in Clojure (on JVM) having the same value are the same atom? (ie how does Clojure's atom storage mechanism work?)
First, "atom" has a different meaning in Clojure than in most other Lisps. See http://clojure.org/atoms
Clojure's =
function uses value-based equality. So two objects with equal values will be =
even if they are stored in different locations in memory.
To test if two objects are actually the same object, at the same address in memory, use the identical?
function.
I think 'a and 'a are going to be different Java objects under the hood. I believe this confirms that suspicion:
user> (def foo 5)
#'user/foo
user> (System/identityHashCode 'foo)
578999228
user> (System/identityHashCode 'foo)
1724482638
If you look at the actual implementation of Symbol in Clojure, you'll see that a symbol consists of a namespace and a name and those Strings MUST be interned strings. The Symbol.equals() method relies on doing identity checks on those two strings, relying on string intern.
I'll explain the Common Lisp part:
In Common Lisp (eq 'a 'a) returns always T.
Reason: at read time, the reader looks up a, and for both a it will look up the same symbol a. Since any symbol is EQ to itself, the expression returns always T.
This is true for most types of objects, but with a few exceptions. Numbers and characters, for example, are not necessary EQ in Common Lisp. The reason for that is efficiency. To compare these if they are the same number or same character one can use the function EQL.
To add to Alex's and Stuart's answers, Symbols in Clojure could not be made to be identical?
whenever they are =
mostly because they may carry metadata. Two Symbols which have the same .name
and .namespace
components but different metadata will be =
but not identical?
.
Things could conceivably be arranged so that two Symbols with the same metadata, namespace and name would always be identical?
, but that is (1) two much hassle for no real gain (since you'd still have some Symbols =
but not identical?
), (2) contrary to the idea that types which may carry metadata should normally be compared for value equality (to which metadata does not contribute), whereas actual pointer equality should be reserved for special situations (mostly involving interop).
Note that Clojure Keywords are a separate type for which =
is indeed equivalent to identical?
. (So clearly they cannot have metadata attached.)
精彩评论