You can use the #.
reader macro to get symbolic case labels in Common Lisp. Example:
(defconstant +foo+ 1)
(defconstant +bar+ 2)
(defun quux (x)
(ecase x
(#.+foo+ "Foo!")
(#.+bar+ "Bar.")))
This works in all implementations I tried in the REPL or when loading it from a file.
When using compile-file
(or building via asdf), behavior differs, though. In SBCL it works, but CCL reports an error: Error: Unbound variable: +FOO+
Wrapping the defconstant
s in eval-when
allows compiling in both SBCL and Clozure CL:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +foo+ 1)
(defconstant +bar+ 2))
My question is whether the behavior of CCL conforms to the standard; that is, does portable code require using eval-when
in this scenario? I've read the sections on
defconstant
and compilation in CLTL2, and the remarks about the special behavior of defconstant
in compiled code indicate that it should work without eval-when
.
But I'm interested in the language-lawyer answer.
Yes, CCL is conforming. The standard says
An implementation may choose to evaluate the value-form at compile time, load time, or both.
Therefore if you want to use the value of the constant at read time, which is normally before load time which is the latest time that the constant can have a value, you must ensure that both the compile and load times of the defconstant
form are before the read time of the place you want to use it. That's what eval-when
is for.
In fact the situation is stronger than this: a program which doesn't use eval-when
when the defconstant
is in the same file as the read time use of the constant variable is not conforming (may not be compilable), although a conforming implementation may process it correctly. So SBCL is allowed to do what it does, but CCL is also allowed to reject your program.