4.5. その他の特定子(まだCLOSオブジェクトは不要です)

これまでに挙げたメソッドの例では、すべて standard-class クラスのサブクラスを特定子としていました。しかしそうでなくても、どんなCLOSクラスでも特定化することができます。例えば3.4節で挙げたクラスや、構造体クラスです。

; 構造体クラスを特定子とする
CL-USER 69 > (defmethod my-describe ((self structure-object))
               (format t "~s is a structure object."
                       self))
#<STANDARD-METHOD MY-DESCRIBE NIL (STRUCTURE-OBJECT) 205F5744>
 
; foo は構造体クラスのインスタンス
CL-USER 70 > (my-describe (make-foo))
#S(FOO) is a structure object.
NIL
 
; foo クラス(構造体クラスのサブクラス)を特定子とする
CL-USER 71 > (defmethod my-describe ((self foo))
               (format t "bar"))
#<STANDARD-METHOD MY-DESCRIBE NIL (FOO) 205F3ADC>
 
CL-USER 72 > (my-describe (make-foo))
bar
NIL
 
CL-USER 73 >

CLOSクラスをまったく定義しなくてもメソッドを使えますし、メソッドをまったく定義しなくてもCLOSクラスを使えます。CLOSの二つの要素は独立していて、一度の買い物で二つのオブジェクトシステムがついてきたようなものです。

場合によっては便利なもう一つの特定子のフォームは、eql 引数特定子として知られています。次の例では、特定子のクラス名をあるリストに変更しています。このリストの最初の要素は eql シンボル、次の要素は任意のLispフォームです。このフォームは defmethod で定義したときに評価されます。メソッドを適用可能にするために、フォームの評価値と引数が eql で比較されます。eql メソッドはクラスを特定子とするメソッドよりも優先されます。

; pi は float 型の定数
CL-USER 73 > (defmethod my-describe ((self (eql pi)))
               (format t "approximately 22/7"))
#<STANDARD-METHOD MY-DESCRIBE NIL ((EQL 3.141592653589793)) 2060E57C>
 
CL-USER 74 > (defmethod my-describe ((self float))
                (format t "some float"))
#<STANDARD-METHOD MY-DESCRIBE NIL (FLOAT) 2061EEF4>
 
; eql 引数特定子のメソッドが優先される
CL-USER 75 > (my-describe pi)
approximately 22/7
NIL
 
CL-USER 76 >

練習問題

  • リストのための my-describe メソッドを書きなさい。
  • antelope クラスのインスタンス Eric のための print-object メソッドを書きなさい。Eric のクラスを変更しても、そのメソッドはまだ適用可能だと思いますか?