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?
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)