2

I am very surprised by the behaviour of identical? in clojure.

(def a (map identity [:a :b])) (identical? (rest a) (rest a)); false

Any idea why identical? returns false?

viebel
  • 19,372
  • 10
  • 49
  • 83

2 Answers2

5

identical?:

Tests if 2 arguments are the same object

Since rest creates a new seq object on each invocation, its results are not identical?. The following, however, is:

(def r (rest (map identity [:a :b])))
(identical? r r) ;; => true

Update: As @mfikes pointed out, rest does not always create a new seq. It calls ISeq.more() internally which is implemented per seq type and might yield different results for lists, vectors, lazy seqs, etc.:

(->> [(map identity [:a :b])
      (vector :a :b)
      (list :a :b)]
     (map #(identical? (rest %) (rest %))))
;; => [false false true]
xsc
  • 5,983
  • 23
  • 30
  • so what is the suggested way to check if a sequence is the rest of another sequence? I mean, `pointerwise` and not `by-value` – viebel Dec 14 '14 at 10:51
  • Maybe something along the lines of `(every? true? (map identical? sqa sqb))`? Additionally checking for length equality might be required, though. – xsc Dec 14 '14 at 11:45
  • 1
    Where is it documented that `rest` creates a new seq? – viebel Dec 14 '14 at 13:05
  • 2
    While `rest` doesn't create a new seq object in general, it does for this sequence. It doesn't for list literals, for example. – Mike Fikes Dec 14 '14 at 13:40
  • @mfikes True, I adjusted the answer. – xsc Dec 14 '14 at 14:29
2

identical? is the object equality predicate. It returns true if its arguments are the same object/primitive.

Use = over identical?.

identical? is the correct tool when semantics depend on pointer equality, such as testing for an end-of-file sentinel value.

Never use identical? to compare Clojure data structures. Even keywords don't guarantee identical? behaves correctly.

Ambrose
  • 1,220
  • 12
  • 18