Using SBCL, I have the problem that my system defined via ASDF does not load, when the lisp code defines a string constant. Here's the code:
constants.lisp
(defconstant A 1.0)
(defconstant B "B")
simple.asd
(defsystem :simple
:components ((:file "constants")))
On loading via
(asdf:load-system "simple")
I'm getting the following error (output has been shortened a bit):
* (asdf:load-system "simple")
; compiling file "/Users/.../constants.lisp"
; compiling (DEFCONSTANT A ...)
; compiling (DEFCONSTANT B ...)
; /Users/.../constants-TMP.fasl written
; compilation finished in 0:00:00.003
debugger invoked on a DEFCONSTANT-UNEQL in thread
#<THREAD "main thread" RUNNING {1002BFEA93}>:
The constant B is being redefined (from "B" to "B")
The error does not come up with clisp, ccl and abcl. Also, loading the file via
(load "constants.lisp")
works fine.
I'm using
SBCL 1.2.14, ASDF 3.1.3, MacOS
Thanks for any hints,
Oliver
The specification for defconstant
tells us that:
However, the consequences are undefined if an attempt is made to assign a value to the symbol using another operator, or to assign it to a different value using a subsequent defconstant.
The important word here is different: according to which comparison?
The consequences are undefined if there are any bindings of the variable named by name at the time defconstant is executed or if the value is not eql to the value of initial-value.
The comparison is done by eql.
SBCL compiles your file and then loads the result (the xxx-TMP.fasl
file), and for that particular implementation, the defconstant
form is thus evaluated twice in the same environment. A compiler needs not actually evaluate the form during compilation (it could declare it internally somehow so that further uses of the constants can be inlined) but this is a valid compilation strategy.
Here, since the compilation environment and the load environment are the same, and because the two occurences of the strings are not identical (not eq), an error is signaled. If you happened to load the FASL file with another instance of the same version of the SBCL interpreter, it would not give you this error.
Don't reinvent the wheel, use alexandria:define-constant
, which allows to specify under which test function the value is constant:
(alexandria:define-constant b "B" :test #'string=)
Thus, when it is evaluated multiple times, the new "B"
value is compared against the existing value using string=
, and since they are equal, no other action is performed.
Use defvar
and do not worry about it anymore until you deploy your code (often constants need to change during development).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With