defmethod
(defmethod name [qualifier] (param... ) body...)
総称関数 name にメソッドを追加し、名前シンボルを返します(先行する defgeneric がなければ総称関数を暗黙に作ります)。specializer を付けられるのは 第 1 引数のみで、(var specializer) と書きます:
(var (eql literal))— 第 1 引数がそのリテラル(キーワード、クォートされたシンボル、数値、文字)のときにマッチ(var class-name)—defclassクラスとそのサブクラスのインスタンスにマッチ(var type-name)— 組み込み型(integer、float、number、string、symbol、keyword、character、cons、list、null、hash-table、functionなど)にマッチ(var t)または素のvar— デフォルトメソッド
呼び出しはマッチする最も特定的なメソッドを実行します: まず eql メソッド、次にクラスメソッド(サブクラスがスーパークラスより先)、次に組み込み型(integer のようなサブタイプが number のようなスーパータイプより先)、最後にデフォルトメソッドの順で、マッチがなければエラーを通知します。同じ specializer を再定義すると以前のメソッドを置き換えます。本体はドキュメント文字列と (declare ...) で始められます(どちらも無視されます)。
メソッド修飾子と call-next-method
ラムダリストの前に :before、:after、:around の修飾子を置くと補助メソッドを追加できます(標準メソッド結合)。1 回の呼び出しでは:
- 適用される
:aroundメソッドが最も特定的なものから順に実行され、それぞれが残りをラップします。 - 次に
:beforeメソッドが最も特定的なものから順に副作用として実行されます。 - 次に最も特定的な基本(修飾子なし)メソッドが実行され、その値が結果になります。
- 最後に
:afterメソッドが最も特定的でないものから順に副作用として実行されます。
基本メソッドや :around メソッドの中では、(call-next-method) が次に特定的でないメソッドを呼び出し(現在の引数を渡し、(call-next-method arg...) と書けば新しい引数を渡します)、(next-method-p) はそのようなメソッドが存在するかを返します。次のメソッドがない状態で call-next-method を呼ぶとエラーになります。
ライトサブセット: 必須引数のみで、第 2 引数以降の specializer はエラー、標準メソッド結合はクラスメソッドとデフォルトメソッドについてサポートされます(eql や組み込み型の specializer を持つ :around/:before/:after は、同じ specializer の基本メソッドとデフォルトメソッドのみと結合します)。コンパイルパスでは defmethod はトップレベルフォームとしてのみサポートされ、コンパイルされたプログラムのメソッド集合はコンパイル時に固定されます。