% Standard-Generic-Function CHANGE-CLASS
Standard Generic Function CHANGE-CLASS
change-class
instance new-class &key &allow-other-keys => instance
change-class
(instance standard-object
)
(new-class standard-class
) &rest initargs
change-class
(instance t
)
(new-class symbol
) &rest initargs
instance - オブジェクト
new-class - クラス指定子
initargs - 初期化引数リスト
ジェネリック関数change-class
は、
instanceのクラスをnew-classに変更します。
変更は破壊的な修正を行い、instanceを返却します。
もし元のクラスに、new-classの局所スロットと
同じ名前のスロットが存在する場合は、
そのスロットの値は保持されます。
これは、もしスロットに値があるとき、
change-class
実行後のslot-value
の返却値と、
change-class
実行前のslot-value
の返却値は、
eql
であるという意味です。
同様に、スロットがunbound
のときは、unbound
が保持されます。
他のスロットは、7.2. インスタンスのクラスの変更で記載されたように初期化されます。
他の全ての動作が完了した後で、
change-class
はupdate-instance-for-different-class
を実行します。
ジェネリック関数update-instance-for-different-class
は、
変更されたinstanceのスロットに値を割り当てるときに使用できます。
7.2.2. 新しく追加された局所スロットの初期化を確認ください。
もし、上記のメソッドの2番目が選ばれたとき、
そのメソッドはchange-class
の引数を、
instance、(find-class new-class)
、initargsで起動します。
(defclass position () ())
(defclass x-y-position (position)
((x :initform 0 :initarg :x)
(y :initform 0 :initarg :y)))
(defclass rho-theta-position (position)
((rho :initform 0)
(theta :initform 0)))
(defmethod update-instance-for-different-class :before ((old x-y-position)
(new rho-theta-position)
&key)
;; 位置情報をoldからnewへコピーします。
;; 新しく作成されるrho-theta-positionは古い位置と同じです
(let ((x (slot-value old 'x))
(y (slot-value old 'y)))
(setf (slot-value new 'rho) (sqrt (+ (* x x) (* y y)))
(slot-value new 'theta) (atan y x))))
;;; この時点で、クラスx-y-positionのインスタンスは
;;; chage-classでクラスrho-theta-positionのインスタンスに変更できます
(setq p1 (make-instance 'x-y-position :x 2 :y 0))
(change-class p1 'rho-theta-position)
;;; 結果p1のインスタンスはrho-theta-positionクラスのインスタンスとなりました。
;;; update-instance-for-different-class メソッドは、
;;; 古いインスタンスが保持していたxとyのスロットの値に基づいて
;;; rhoとthetaのスロットの初期化しました。
なし。
なし。
update-instance-for-different-class
, 7.2. インスタンスのクラスの変更
ジェネリック関数change-class
は、
いくつか意味として難しいことがあります。
第一に、これは破壊的なオペレーションであり、
あるメソッドの選択に使われたインスタンスに対して、
そのメソッド内で実行できるという点があげられます。
メソッドが結合されているときに複数のメソッドが巻き込まれると、
現在実行されているメソッドやこれから実行されるメソッドが
適用できなくなることがあります。
第二に、処理系によってはスロットアクセスに
コンパイラの最適化を用いている場合があり、
インスタンスのクラスが変更されると
コンパイラの想定に反してしまう可能性があります。
これは、プログラマがメソッド内部でchange-class
を
使ってはいけないということを意味しており、
もしそのジェネリック関数のメソッドが
何らかのスロットにアクセスすれば、結果は未定義になります。