common-lisp Equality and other comparison predicates The difference between EQ and EQL


  1. EQ checks if two values have the same address of memory: in other words, it checks if the two values are are actually the same, identical object. So, it is can be considered the identity test, and should be applied only to structures: conses, arrays, structures, objects, typically to see if you are dealing in fact with the same object “reached” through different paths, or aliased through different variables.

  2. EQL checks if two structures are the same object (like EQ) or if they are the same non-structured values (that is, the same numeric values for numbers of the same type or the character values). Since it includes the EQ operator and can be used also on non-structured values, is the most important and most commonly used operator, and almost all the primitive functions that require an equality comparison, like MEMBER, use by default this operator.

So, it is always true that (EQ X Y) implies (EQL X Y), while the viceversa does not hold.

A few examples can clear the difference between the two operators:

(eq 'a 'a)
T ;; => since two s-expressions (QUOTE A) are “internalized” as the same symbol by the reader.
(eq (list 'a) (list 'a))
NIL ;; => here two lists are generated as different objects in memory
(let* ((l1 (list 'a))
       (l2 l1))
  (eq l1 l2))
T ;; => here there is only one list which is accessed through two different variables
(eq 1 1)
?? ;; it depends on the implementation: it could be either T or NIL if integers are “boxed”
(eq #\a #\a)
?? ;; it depends on the implementation, like for numbers
(eq 2d0 2d0)
?? ;; => dependes on the implementation, but usually is NIL, since numbers in double 
   ;;    precision are treated as structures in many implementations
(let ((a1 2d0)
      (a2 2d0))
  (eq a1 a2))
?? ;; => also in this case the results depends on the implementation

Let’s try the same examples with EQL:

(eql 'a 'a)
T ;; => equal because they are the same value, as for EQ
(eql (list 'a) (list 'a))
NIL ;; => different because they different objects in memory, as for EQ
(let* ((l1 (list 'a))
       (l2 l1))
  (eql l1 l2))
T ;; => as above
(eql 1 1)
T ;; they are the same number, even if integers are “boxed”
(eql #\a #\a)
T ;; they are the same character
(eql 2d0 2d0)
T ;; => they are the same number, even if numbers in double precision are treated as
   ;;   structures in many implementations
(let ((a1 2d0)
      (a2 2d0))
  (eql a1 a2))
T ;; => as before
(eql 2 2.0)
NIL;; => since the two values are of a different numeric type

From the examples we can see why the EQL operator should be used to portably check for “sameness” for all the values, structured and non-structured, and why actually many experts advise against the use of EQ in general.