lispcommon-lispclos

Vectors of CLOS objects in Common Lisp


I'm running into strange behaviour I'm unable to explain in Common Lisp (SBCL 2.3.4). Consider the following test case:

(defclass class-a ()
  ((foobar :initarg :foobar
       :accessor foobar
       :initform '(foo bar))))

(defclass class-b ()
  ((something :initarg :something
          :accessor something)))

(defvar *instance-a* (make-instance 'class-a))
(defvar *instance-b* (make-instance 'class-b :something *instance-a*))

If I inspect instance-b in the REPL I can see that the something variable has been set:

CL-USER> (slot-value *instance-b* 'something)
#<CLASS-A {7007C70C53}>

However if I try to create a trivial vector of these objects, the object appears to "lose track", for lack of a better term, of its bindings:

CL-USER> (slot-value (elt #(*instance-b*) 0) 'something)
; Debugger entered on #<SB-PCL::MISSING-SLOT SOMETHING {7008E5A1E3}>

When attempting to read the slot's value (slot-value), the slot
SOMETHING is missing from the object *INSTANCE-B*.
   [Condition of type SB-PCL::MISSING-SLOT]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD "sly-channel-1-mrepl-remote-1" RUNNING {70052925C3}>)

Backtrace:
 0: ((:METHOD SLOT-MISSING (T T T T)) #<BUILT-IN-CLASS COMMON-LISP:SYMBOL> *INSTANCE-B* SOMETHING SLOT-VALUE NIL) [fast-method]
 1: (SLOT-VALUE *INSTANCE-B* SOMETHING)
 2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SLOT-VALUE (ELT #(*INSTANCE-B*) 0) (QUOTE SOMETHING)) #<NULL-LEXENV>)
 3: (EVAL (SLOT-VALUE (ELT #(*INSTANCE-B*) 0) (QUOTE SOMETHING)))

What is happening here?


Solution

  • Actually this problem is not related to CLOS, but about how to create vectors with data.

    CL-USER 4 > #(*instance-b*)
    #(*INSTANCE-B*)
    
    CL-USER 5 > (aref #(*instance-b*) 0)
    *INSTANCE-B*
    
    CL-USER 6 > (type-of (aref #(*instance-b*) 0))
    SYMBOL
    

    The vector does not contain an instance of some CLOS class, but a symbol.

    If we write down a literal vector like #((+ 1 2)), then the subexpression (+ 1 2) is not evaluated.

    To create vectors use: (vector (+ 1 2)) -> #(3)

    The backquote notation also works for vectors:

    `#(,(+ 1 2))
    
     -> #(3)
    

    You can use:

    (slot-value (elt `#(,*instance-b*) 0) 'something)
    

    or

    (slot-value (elt (vector *instance-b*) 0) 'something)