Macro DEFGENERIC
defgeneric function-name gf-lambda-list [[option | method-description*]]
=> new-generic
option ::= (:argument-precedence-order parameter-name+) |
(declare gf-declaration+) |
(:documentation gf-documentation) |
(:method-combination method-combination method-combination-argument*) |
(:generic-function-class generic-function-class) |
(:method-class method-class)
method-description ::=
(:method method-qualifier* specialized-lambda-list
[[declaration* | documentation]] form*)
function-name - 関数名
generic-function-class - nilではない、クラス名のシンボル
gf-declaration - optimizeの宣言指定子。他の宣言指定子は許されません。
gf-documentation - 文字列(評価はされない)
gf-lambda-list - ジェネリック関数のラムダリスト
method-class - nilではない、クラス名のシンボル
method-combination-argument - オブジェクト
method-combination-name - nilではない、method-combinationの型の名前のシンボル
method-qualifiers, specialized-lambda-list, declarations, documentation, forms - defmethodに従います。
new-generic - ジェネリック関数オブジェクト
parameter-name - ラムダリスト内にある要求パラメーターの名前のシンボル。 (もし:argument-precedence-orderオプションが定義されているならば、 ラムダリスト内のそれぞれの要求パラメーターは、 parameter-nameが正確にひとつ使われなければなりません)
マクロdefgenericは、ジェネリック関数を定義したり、 ジェネリック関数全体に関わるオプションと宣言を指定するときに使われます。
もしfunction-nameがリストなら、(setf symbol)の形式でなければなりません。 もし(fboundp function-name)がfalseのときは、新しいジェネリック関数が作成されます。 もし(fdefinition function-name)がジェネリック関数のときは、 そのジェネリック関数は変更されます。 もしfunction-nameが通常の関数か、マクロか、特殊オペレーターの名前のときは、 エラーが発生します。
defgenericマクロは、次に示す3つのステップが実行されたかのような効果を示します。 第一に、以前defgenericフォームで定義されたメソッドは削除されます。 第二に、ensure-generic-functionが呼び出されます。 そして最後に、今回のdefgenericフォームによって定義されたメソッドが、 ジェネリック関数に追加されます。
各method-descriptionは、そのジェネリック関数上で、メソッドが宣言されます。 各メソッドのラムダリストは、gf-lambda-listオプションによって指定された ラムダリストと合致しなければなりません。 メソッドの定義が指定されておらず、 同名のジェネリック関数が存在しない場合は、 メソッドがないジェネリック関数が作成されます。
defgenericの引数gf-lambda-listは、 そのジェネリック関数のメソッドに対して、 ラムダリストの形を指定します。 返却されるジェネリック関数上の全てのメソッドは、 この形に合致したラムダリストを持たなければなりません。 もし、defgenericフォームが評価されたとき、 そのジェネリック関数にあるメソッドのラムダリストが defgenericフォームに付与されたものと合致しない場合は、 エラーが発生します。 メソッドの合致に関するさらなる詳細は、7.6.4. ジェネリック関数の全てのメソッドのラムダリストの合意をご確認ください。
ジェネリック関数は、渡されたすべての引数をメソッドに渡します。 渡されるのはそれらの値のみであり、デフォルト値は供給されません。 ただし、メソッド定義にはオプション引数とキーワード引数があり、 デフォルト値とsupplied-pパラメーターが使用できることに注意してください。
次に示すオプションが提供されます。 注意書きがあるもの以外、オプションはただひとつ与えられます。
:argument-precedence-orderは、 ジェネリック関数が呼び出だされ、特定のメソッドを選択するときに テストを行う要求された引数の順序を指定するために使用されます。 完全かつ曖昧がないような優先順序が与えられるように、 gf-lambda-list引数内で指定されたそれぞれのrequired-arguments}は、 正確にひとつだけparameter-nameとして含まれなければなりません。 もしこのような条件に合わない場合は、エラーが発生します。declareのオプションは、 ジェネリック関数に関する宣言を指定するときに使われます。
optimize宣言指定子が許されます。 この宣言は、メソッドの選択の最適化がspeedかspaceなのかを指定するものであり、 メソッドへの効果はありません。 メソッドの最適化をどのように制御するかについては、 optimize宣言をdefmethodかメソッドの宣言内に 直接記載する必要があります。 標準で要求される最適化の種類はspeedとspaceだけですが、 実装によっては他の種類も認識するように、 オブジェクトシステムを拡張することもできます。 単純な実装では、メソッドの選出方法をただひとつだけ実装し、 optimize宣言指定子を無視するというのが有効です。special, ftype, function, inline, notinline, declarationの宣言は許されていません。 各実装は、declareオプションを拡張して、 追加の宣言をサポートすることができます。 もしある実装が、サポートしていない宣言指定子に遭遇し、 その宣言が非標準の宣言の名前でproclaimされていた場合は、 警告を発生させるべきです。declareオプションは、複数指定されるかもしれません。 宣言指定子のリストをひとつにまとめて、 単体のdeclareオプションとして指定したのと同じ効果が得られます。:documentationは、ジェネリック関数のオブジェクトにドキュメント文字を、 種類functionで、funciton-nameに割り当てられます。:generic-function-classオプションは、 ジェネリック関数が、システムの提供するデフォルトのもの (standard-generic-functionのクラス)とは 異なるクラスを持つことを指定するために使われます。 引数class-nameは、ジェネリック関数クラスのクラス名です。 もし、function-nameが既存のジェネリック関数を示しており、 新しいジェネリック関数の:generic-function-classの値が 古いものと互換性がある場合は、 change-classが呼ばれてジェネリック関数のクラスが変更されます。 それ以外の場合はエラーが発生します。:method-classオプションは、 ジェネリック関数上の全てのメソッドが、 システムの提供するデフォルトのもの(standard-methodのクラス)とは 異なるクラスを持つことを指定するために使われます。 引数class-nameは、メソッドのクラスとなりえるクラス名です。:method-combinationオプションは、 method-combinationの型の名前であるシンボルが続きます。 そのシンボルの後に続く引数があるなら、それはmethod-combinationの型に依存します。 standardのmethod-combinationは、引数をサポートしません。 しかし、define-method-combinationの短縮形によって宣言された method-combinationの型は全て、orderというオプション引数を受け付けます。 デフォルトの値は:most-specific-firstであり、 もしこの値が:most-specific-lastのときは、 補助メソッドの順番に影響を与えずに、プライマリメソッドの順番を逆転させます。引数method-descriptionは、ジェネリック関数に関連付けたメソッドを宣言できます。 メソッド宣言にある引数のmethod-qualifierとspecialized-lambda-listは、 defmethodと同じです。
引数formは、メソッドのボディ部です。 メソッドのボディ部は、暗黙のblockで囲まれます。 もしfunction-nameがシンボルのとき、 blockの名前はジェネリック関数と同じ名前です。 もしfunction-nameが(setf symbol)のリスト形式の場合は、 blockの名前はsymbolです。
実装は、defgenericに別のオプションを含めるよう拡張できます。 もし自身が実装していないオプションが見られた場合は、 その実装はエラーを発生するよう要求されます。
defgenericは、コンパイル時にはどのような副作用も要求されていません。 特に、コンパイル時に呼び出すためのメソッドは導入されません。 実装者は、コンパイル時のエラーチェック (関数呼び出し時の引数の個数チェックであったり、 あるいは関数名の定義を確認したりすること)のために、 ジェネリック関数についての情報を保存するか選択できます。
なし。
なし。
もしfunction-nameが通常の関数か、マクロか、特殊オペレーターの名前のときは、 型program-errorのエラーが発生します。
引数gf-lambda-listとして指定された各要求された引数は、 parameter-nameとして正確にひとつだけ含まれなければならず、 そうでないときは、型program-errorのエラーが発生します。
method-descriptionによって指定された各メソッドのラムダリストは、 gf-lambda-listオプションによって指定されたラムダリストと合致していなければならず、 そうでないときは型errorのエラーが発生します。
もし、defgenericフォームが評価されたとき、 そのジェネリック関数にあるメソッドのラムダリストが defgenericフォームに付与されたものと合致しない場合は、 型errorのエラーが発生します。
オプションがただひとつではなかった場合は、 型program-errorのエラーが発生します。
もし、function-nameが既存のジェネリック関数を示しており、 新しいジェネリック関数の:generic-function-classの値が 古いものと互換性がある場合は、 change-classが呼ばれてジェネリック関数のクラスが変更されます。 それ以外の場合は型errorのエラーが発生します。
実装は、defgenericに別のオプションを含めるよう拡張できます。 もし自身が実装していないオプションが見られた場合は、 その実装は型program-errorのエラーを発生するよう要求されます。
defmethod, documentation, ensure-generic-function, generic-function, 7.6.4. ジェネリック関数の全てのメソッドのラムダリストの合意
なし。