SBCL: asdf:load-system fails when a string constant is defined

Why does the string constant fails?

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.

What can you do?

  1. 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.

  2. Use defvar and do not worry about it anymore until you deploy your code (often constants need to change during development).