カプセル化された class を定義
unintern でカプセル化を実現 - Shammerismで、package を使って global 変数への書き込みや参照にアクセサが必要なようにしてみた。ただ、package でできたのだから class でもできないか、と思いちょっとやってみた。
? (defclass foo () ((x))) #<STANDARD-CLASS FOO> ? (defmethod get-x ((vo foo)) (slot-value vo 'x)) #<STANDARD-METHOD GET-X (FOO)> ? (defmethod set-x ((vo foo) value) (setf (slot-value vo 'x) value)) #<STANDARD-METHOD SET-X (FOO T)> ? (defparameter *foo* (make-instance 'foo)) *FOO* ? (set-x *foo* 10) 10 ? (get-x *foo*) 10 ? (slot-value *foo* x) > Error: Unbound variable: X > While executing: CCL::CHEAP-EVAL-IN-ENVIRONMENT, in process Listener(4). > Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts. > If continued: Retry getting the value of X. > Type :? for other options. 1 > q ? (slot-value x *foo*) > Error: Unbound variable: X > While executing: CCL::CHEAP-EVAL-IN-ENVIRONMENT, in process Listener(4). > Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts. > If continued: Retry getting the value of X. > Type :? for other options. 1 > q ? (slot-value *foo* 'x) 10 ? (unintern 'x) T ? (slot-value *foo* 'x) > Error: #<FOO #x302000D2A2ED> has no slot named X. > While executing: #<CCL::STANDARD-KERNEL-METHOD SLOT-MISSING (T T T T)>, in process Listener(4). > Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts. > If continued: Try accessing the slot again > Type :? for other options. 1 > q ? (get-x *foo*) 10 ? (set-x *foo* 20) 20 ? (get-x *foo*) 20 ?
なんか、色々間違えているなぁ。上の例だと間違いも含めてポイントは以下。
- slot-value でクラス変数を参照する際は、(slot-value $INSTANCE '$INSTANCE_SLOT) という順番。
- SLOT は Quote してやらないといけない。
- unintern した後にできたインスタンス達も slot-value に属性でアクセスできなくなっている。
コード上で、アクセサメソッドが全て定義された後で unintern しないとアクセスできなくなってしまうので、メソッドの定義は完全かを確認できてから unintern するのがよさそうだ。