Standard-Generic-Function CHANGE-CLASS

UP


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-classupdate-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を 使ってはいけないということを意味しており、 もしそのジェネリック関数のメソッドが 何らかのスロットにアクセスすれば、結果は未定義になります。


TOP, Github