シンボルはパッケージや「名前」に従属する存在ではなく、独立した実体を備えたオブジェクトである。
例えば以下のコードでは同じ名前を持つ2つの異なるシンボルを作っている。
(let ((sym1 (make-symbol "name")) (sym2 (make-symbol "name"))) (values (string= (symbol-name sym1) (symbol-name sym2)) (eq sym1 sym2))) ;; => T NIL
これは他のオブジェクト、例えば文字列を make-array で作る場合と、質的には何ら変わりない。
(let ((str1 (make-array 4 :element-type 'character :initial-element #\a)) (str2 (make-array 4 :element-type 'character :initial-element #\a))) (values (string= str1 str2) (eq str1 str2))) ;; => T NIL
パッケージによるオブジェクト同一性の保証
シンボルは単なるオブジェクトなので、「『同じ名前』に対しては常に同じオブジェクトが割り当てられる」という、まさにシンボルがシンボルたる性質は、実はパッケージ・システムによって実現されている。
(let ((sym1 'foo) (sym2 'foo)) (values (string= (symbol-name sym1) (symbol-name sym2)) (eq sym1 sym2))) ;; => T T
マクロにおけるオブジェクト同一性の保証
gensym を使ったマクロを書く場合などは、パッケージ・システムに頼らず自分でシンボル・オブジェクトの同一性を保証していることになる。
(defmacro sym-test () (let ((sym (gensym))) `(eq ',sym ',sym))) ;; => T
上のコードにおいて sym はシンボル・オブジェクトに展開される(シンボルの「名前」ではない)ので、インターンされないシンボルを使っても、オブジェクトの同一性が保たれる。
つまり展開後のコードは、下のコードと等価では無い。
(eq '#:G762 '#:G762) ;; => NIL
展開後のコードに含まれているのは、あくまでもシンボル・オブジェクトである。
(mapcar #'(lambda (c) (class-of (cadr c))) (rest (macroexpand-1 '(sym-test)))) ;; => (#<BUILT-IN-CLASS SYMBOL> #<BUILT-IN-CLASS SYMBOL>)