3

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.

Maris Orbidans
  • 163
  • 2
  • 4

1 Answers1

4

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 defconstant doesn't define the constant at compile time. That means that, when lol is 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:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defconstant +one+ 1)
  (defconstant +two+ 2))

(defun lol (gg)
  (ecase gg
    (#.+one+ :one)
    (#.+two+ :two)))

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.

  • You are right. I was trying to compile this file. Somehow it was compiling just fine in SBCL. – Maris Orbidans Jun 04 '21 at 18:12
  • 1
    "An implementation may choose to evaluate the value-form at compile time, load time, or both." (http://clhs.lisp.se/Body/m_defcon.htm) – coredump Jun 04 '21 at 21:49
  • @coredump: yes, it is (and that's why there's the statement that the value must always be the same). That allows the compiler to treat references to the constant as literals if it wants to by stashing the value in the compilation environment somewhere. But the compiler doesn't actually define the variable at compile time, any more than it should define a function at compile time. An even stronger example of this is macros, of course. –  Jun 05 '21 at 10:32