Vectors of CLOS objects in Common Lisp

111 views Asked by At

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?

1

There are 1 answers

0
Rainer Joswig On BEST ANSWER

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)