たとえば、次のようなpackageとclassを定義したとする。
(in-package :cl-user) (defpackage abc (:use :cl) (:export :<abc>)) (in-package :abc) (defclass <abc> () ((abc :initarg :abc :reader get-abc :documentation "abc"))) (in-package :cl-user) (defpackage def (:use :cl :abc)) (in-package :def) (defclass <def> (<abc>) ((def :initarg :def :reader get-def :documentation "def")))
で、defの中でinstanceを作成。
DEF> (setq wrk (make-instance '<def> :abc "111" :def "222"))
まぁ、WARNINGは多少でるけれど、中身は設定されている。
DEF> (get-def wrk) "222" DEF>
get-abcが効かないのは関数をexportしていないのでDEFから見えていないからだろう。
DEF> (get-abc wrk)
; in: GET-ABC WRK
; (DEF::GET-ABC DEF::WRK)
;
; caught STYLE-WARNING:
; undefined function: GET-ABC
;
; caught WARNING:
; undefined variable: WRK
;
; compilation unit finished
; Undefined function:
; GET-ABC
; Undefined variable:
; WRK
; caught 1 WARNING condition
; caught 1 STYLE-WARNING condition
; Evaluation aborted on #<UNDEFINED-FUNCTION GET-ABC {1003F36EE3}>.
DEF>
ところがslot-valueでabcの中身を見にいってもエラーになる。
DEF> (slot-value wrk 'def)
"222"
DEF> (slot-value wrk 'abc)
; Evaluation aborted on #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
object ~S.~@:>" {10040EC8D3}>.
DEF>
これがしばらく理解できなかった。
というのもelispのEIEIOではうまくいくからだ。
HyperSpecのdefpackageの説明を見ていてexportしているのはsymbol-nameだと気づいた。functionじゃないんだ……。つまりClassの中で定義しているslot-nameもexportしなければ、いけない。
それならこれでも動くはず。
DEF> (slot-value wrk 'abc::abc) "111" DEF>
実際にexportしてやっても動いた。
(defpackage abc
(:use :cl)
(:export :<abc>
:abc))
DEF> (slot-value wrk 'abc) "111" DEF>
EIEIOで動いていていたのはpackageがないからか……。
でもslot-nameなんてばりばり競合してしまうでaccessorをexportするのが、吉なんだろうな……。accessorならmethodなので同じ名前が存在しても競合する可能性はきわめて低いから。