I want to use constant variables in case macro as "Common Lisp Recipes" book recommends.
- 10-2. Using Constant Variables as Keys in CASE Macros
Unfortunately it doesn't work in Clozure CL.
(defpackage #:foo
(:use #:cl))
(in-package #:foo)
(defconstant +one+ 1)
(defconstant +two+ 2)
(defun lol (gg)
(ecase gg
(#.+one+ :one)
(#.+two+ :two)))
This code fails to load.
Unbound variable: FOO::+ONE+
[Condition of type UNBOUND-VARIABLE]
Restarts:
0: [CONTINUE] Retry getting the value of FOO::+ONE+.
1: [USE-VALUE] Specify a value of FOO::+ONE+ to use this time.
2: [STORE-VALUE] Specify a value of FOO::+ONE+ to store and use.
The code works fine in SBCL. Why doesn't it work in CCL?
I am using 64 bit Clozure CL 1.12 on macOS.
CCL will happily load the source of this file for me, and I believe that any CL should do so.
What it won't do, and what I would be surprised if any CL will do, is compile it. It won't compile it because
defconstantdoesn't define the constant at compile time. That means that, whenlolis compiled, there is a reference to a not-yet-defined variable.If you want to treat constants like this you need to make sure the variables are defined at compile time. There are two ways of doing this:
Firstly you can just add suitable
eval-whenery, after which the relevant chunk of source will be:The second is to put the constants in their own file which is compiled and loaded before they are used. Typically that's managed with a system-definition facility like ASDF.
Note: I believe that any CL should be able to load the source because, I think, even compiler-only implementations are required, when loading source code files, to treat them a form at a time: I don't think it is legal to turn
(load "foo.lisp")into(load (compile-file "foo.lisp"))in other words. I might be wrong about that however: it's a long time since I read the spec that forensically.