Search code examples
common-lispsbclclosquicklispasdf

Loading a file that specifies an error form, but getting the error


I'm trying to write a small game in (SBCL) Common Lisp, using Quickload and ASDF to define and manage dependencies. It uses CLOS, so I have a directory in project called classes, and in there, a file, locatable.cl.

The defclass form for the LOCATABLE class needs a LOCATOR parameter, so I have a line:

:initform (error "Must supply a locator parameter for this class.")

Whenever I try to load this file or quickload the system, though, I get the error above ("Must supply a locator parameter for this class"). Since I'm trying to define a system and not creating any instances of the class, I don't understand why I'm getting this. If I comment out the error line, everything loads fine, but I was led to believe that the way I have it is a standard way of requiring an :initval for a slot.

How do you define such a thing so you can load the file/make a system definition without actually signaling the error?

Here's the class -

(defclass locatable ()
  ((zone
    :accessor zone
    :initform nil)
   (locator
    :initarg :locator
    :initform (error "Must supply a locator parameter for this class.")
    :allocation :class
    :accessor locator)))

UPDATE: I entered the form at the REPL and got the same error. For curiosity's sake, I entered it in again twice, first with :initform "", then with the error form. It accepted the first form, and didn't complain about the second, so this problem doesn't seem to happen on re-definition.


Solution

  • (defclass locatable ()
      ((zone
        :accessor zone
        :initform nil)
       (locator
        :initarg :locator
        :initform (error "Must supply a locator parameter for this class.")
        :allocation :class
        :accessor locator)))
    

    The slot locator is shared in the class. It will be allocated somehow in the class object. The DEFCLASS form creates this class object. Thus the slot locator usually will be initialized when the class object is created and initialized. Way before the first instance of that class is created.

    LispWorks Backtrace

    CL-USER 50 : 1 > :b
    Call to CLOS::CLASS-REDEFINITION-LOCK-DEBUGGER-WRAPPER
    Call to INVOKE-DEBUGGER
    Call to ERROR
    Call to (METHOD CLOS::COMPUTE-CLASS-SLOT-CONSES (STANDARD-CLASS))
    Call to (METHOD SHARED-INITIALIZE :AFTER (STANDARD-CLASS T))    ; <--
    Call to CLOS::ENSURE-CLASS-USING-CLASS-INTERNAL
    Call to (METHOD CLOS:ENSURE-CLASS-USING-CLASS (CLASS T))
    Call to CLOS::ENSURE-CLASS-WITHOUT-LOD
    Call to LET
    Call to LET
    Call to EVAL
    Call to CAPI::CAPI-TOP-LEVEL-FUNCTION
    Call to CAPI::INTERACTIVE-PANE-TOP-LOOP
    Call to MP::PROCESS-SG-FUNCTION
    

    As you see SHARED-INITIALIZE is called on the class object, which then initializes the shared slots.

    I also don't think calling error like this should be done in user code. You might find a better way to check for missing initargs.