I'd be as glad if we decided that IMPORT into the keyword package is
non-conforming.
Notice that INTERN is described in terms of "entering a symbol into the
package [as an internal or external symbol]", while IMPORT says "import
adds symbol or symbols to the internals of package" and 11.1.2.3.1 only
talks about interning the symbol.
So it seems that what's specified is that import doesn't necessarily
make a symbol a keyword (it sets the symbol-package only of homeless
symbols), and that it doesn't make them constants bound to themselves,
and I notice now that it doesn't make them external either. On the
other hand, the :keyword syntax interns a symbol in the keyword package
be it external or not, so when you use it, you may get an internal
symbols, an unbound symbol, and if you evaluate it, a different value.
If you have imported symbols in KEYWORD, you should better quote your
keywords!
So what's currently specified is that:
[pjb@kuiper :0 ~]$ cat keyword-test.lisp
(defun full-keyword-p (object)
(and (symbolp object)
(eq (symbol-package object) (find-package :keyword))
#|ie.|# (keywordp object)
(boundp object)
(eq (symbol-value object) object)
(constantp object)))
(defun keyword-without-constant-value-p (object)
(and (symbolp object)
(eq (symbol-package object) (find-package :keyword))
#|ie.|# (keywordp object)
(not (and (boundp object)
(eq (symbol-value object) object)
(constantp object)))))
(defun not-a-keyword/unbound-p (object)
(and (symbolp object)
(not (eq (symbol-package object) (find-package :keyword)))
#|ie.|# (not (keywordp object))
(not (boundp object))))
(defun not-a-keyword/bound-p (object)
(and (symbolp object)
(not (eq (symbol-package object) (find-package :keyword)))
#|ie.|# (not (keywordp object))
(boundp object)))
(defmacro report (&body body)
`(multiple-value-bind (object name) (progn ,@body)
(let ((before-intern (list (full-keyword-p object)
(keyword-without-constant-value-p object)
(not-a-keyword/unbound-p object)
(not-a-keyword/bound-p object)))
(find-symbol-result (multiple-value-list (find-symbol name :keyword)))
(interned (intern name :keyword))
(after-intern (list (full-keyword-p object)
(keyword-without-constant-value-p object)
(not-a-keyword/unbound-p object)
(not-a-keyword/bound-p object))))
(print (append (list (and (equalp before-intern after-intern)
(eq object interned)))
(list before-intern)
find-symbol-result)))))
(report (unintern ':normal-keyword :keyword)
(let ((object (intern "NORMAL-KEYWORD" :keyword)))
(values object "NORMAL-KEYWORD")))
;; --> (T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(report (unintern ':homeless-symbol :keyword)
(let ((object (make-symbol "HOMELESS-SYMBOL")))
(import object :keyword)
(values object "HOMELESS-SYMBOL")))
;; --> (T (NIL T NIL NIL) :HOMELESS-SYMBOL :INTERNAL)
(report (unintern ':unbound-symbol :keyword)
(unintern 'cl-user::unbound-symbol :cl-user)
(let ((object (intern "UNBOUND-SYMBOL" :cl-user)))
(makunbound object)
(import object :keyword)
(values object "UNBOUND-SYMBOL")))
;; --> (T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :INTERNAL)
(report
(unintern ':bound-symbol :keyword)
(unintern 'cl-user::bound-symbol :cl-user)
(let ((object (intern "BOUND-SYMBOL" :cl-user)))
(setf (symbol-value object) 42)
(import object :keyword)
(values object "BOUND-SYMBOL")))
;; --> (T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :INTERNAL)
[pjb@kuiper :0 ~]$ clall '(progn (load "keyword-test.lisp" :verbose nil) (values))' \
'(quote (:normal-keyword :homeless-symbol :unbound-symbol :bound-symbol))'
# Note: you cannot evaluate :unbound-symbol ;-)
Armed Bear Common Lisp:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (NIL T NIL NIL) :HOMELESS-SYMBOL :INTERNAL)
(T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :INTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :INTERNAL)
Armed Bear Common Lisp:
--> (:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL COMMON-LISP-USER::BOUND-SYMBOL)
International Allegro CL Free Express Edition:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (NIL T NIL NIL) :HOMELESS-SYMBOL :INTERNAL)
(T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :INTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :INTERNAL)
International Allegro CL Free Express Edition:
--> (:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL COMMON-LISP-USER::BOUND-SYMBOL)
Clozure Common Lisp:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (T NIL NIL NIL) :HOMELESS-SYMBOL :EXTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::UNBOUND-SYMBOL :EXTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :EXTERNAL)
Clozure Common Lisp:
--> (:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL COMMON-LISP-USER::BOUND-SYMBOL)
CLISP:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (T NIL NIL NIL) :HOMELESS-SYMBOL :EXTERNAL)
(T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :EXTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :EXTERNAL)
CLISP:
-->
(:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL
COMMON-LISP-USER::BOUND-SYMBOL)
CMU Common Lisp:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (NIL T NIL NIL) :HOMELESS-SYMBOL :INTERNAL)
(T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :INTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :INTERNAL)
CMU Common Lisp:
--> (:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL
COMMON-LISP-USER::BOUND-SYMBOL)
SBCL:
(T (T NIL NIL NIL) :NORMAL-KEYWORD :EXTERNAL)
(T (NIL T NIL NIL) :HOMELESS-SYMBOL :INTERNAL)
(T (NIL NIL T NIL) COMMON-LISP-USER::UNBOUND-SYMBOL :INTERNAL)
(T (NIL NIL NIL T) COMMON-LISP-USER::BOUND-SYMBOL :INTERNAL)
SBCL:
--> (:NORMAL-KEYWORD :HOMELESS-SYMBOL COMMON-LISP-USER::UNBOUND-SYMBOL
COMMON-LISP-USER::BOUND-SYMBOL)
========================================================================
ie. ANSI-TESTs keyword.lsp is entirely wrong, and ccl and clisp need
conformance bug reports.