ジェネリック関数を生成し、name に束縛します。
通常は、これを使う必要はありません。もし、まだ存在していなければ、
define-method
マクロが暗黙裏にジェネリック関数を生成してくれるからです。
キーワード引数class
に、<generic>
のサブクラスを渡すことで、
作られるジェネリック関数をデフォルトの<generic>
クラスのインスタンスでは
なく指定のクラスのインスタンスにすることができます。<generic>
の
サブクラスを定義してメソッド適用をカスタマイズする場合に便利です。
name という名前のメソッドを定義します。すでにグローバルに name に束縛されているジェネリック関数オブジェクトが存在していれば、生成された メソッドはそのジェネリック関数に追加されます。name が未束縛であるか またはジェネリック関数以外に束縛されているなら、新しいジェネリック関数が 生成され、name に束縛されて、新しいメソッドがそれに追加されます。
名前の後に、省略可能なqualifierを置くことができます。 各qualifierはキーワードです。 現在、次のqualifierのみが有効です。
:locked
同じ特定化子(specs)を持つメソッドを再定義しないことを宣言します。 再定義しようとするとエラーが投げられます。 (特定化子の異なるメソッドは定義できます)。
組み込みオブジェクトの基本的な操作に関わるメソッドの多くはロックされています。 それらを再定義してしまうと、Gaucheの基盤が不安定になる恐れがあるからです。 また、最適化が可能になります。
specs はこのメソッドに対応する引数とその型を指定します。これは lambda 形式の引数リストに似ていますが、それぞれの引数の型を指定できる ところが違います。
specs : ( arg ... ) | ( arg ... . symbol ) | ( arg ... extended-spec ...) | symbol arg : ( symbol class ) | symbol
class は引数が所属すべきクラスを指定します。arg
が単に
シンボルであれば、(arg <top>)
と同じです。rest 引数の
型を指定することはできません。それは常にリストに束縛されるからです。
:optional
、:key
、:rest
等の拡張引数指定を使うことも
できます。(拡張引数指定については手続きを作るを参照してください)。
拡張引数指定は、メソッドディスパッチに関しては rest引数と同様に扱われます。
すなわち、省略可能引数やキーワード引数にクラスを指定することはできません。
引数リストのクラスのリストはメソッド特定化子リストといい、
これを基に、ジェネリック関数は適切なメソッドを選択します。specs と
それに対応する特定化子リストの例をあげておきます。
(rest引数は特定化子リストには考慮されないことに注意。リストに決まっているからです。)
optional
の項はメソッドがrest引数を取るかどうかを示します。
specs: ((self <myclass>) (index <integer>) value) specializers: (<myclass> <integer> <top>) optional: #f specs: (obj (attr <string>)) specializers: (<top> <string>) optional: #f specs: ((self <myclass>) obj . options) specializers: (<myclass> <top>) optional: #t specs: ((self <myclass>) obj :optional (a 0) (b 1) :key (c 2)) specializers: (<myclass> <top>) optional: #t specs: args specializers: () optional: #t
その特定化子リストがジェネリック関数の中のメソッドの一つに一致し、 rest引数の有無も同じである name 上のメソッドを定義すると、既存のメソッドは新しく定義された メソッドに置き換えられます。(既存のメソッドがロックされていない限り)。
註: Gaucheがキーワード-シンボル統合モード ((キーワードとシンボルの統合参照)で実行されている場合、 specsが単独のシンボルで、それがキーワードでもあった場合 (引数すべてを単一の変数で受け取る、その変数がキーワードでもあった場合) に曖昧性が生じます。Gaucheではnameに続くキーワードはすべて qualifierとしてパーズするので、単一の変数からなるspecsには キーワードを使わないようにしてください。
ジェネリック関数は適用されると、まず、与えられた引数に適合する
特定化子リストを持つメソッドを選択します。たとえば、ジェネリック関数
foo
が 3つのメソッドを持っており、それらの特定化子リストが
それぞれ、(<string> <top>)
、(<string> <string>)
、
(<top> <top>)
であるとします。foo
が (foo "abc" 3)
の
ように適用されたとき、最初と 3番目のメソッドが選択されます。
選択されたメソッドは、もっとも特定化されたものから、もっとも一般的なものへ の順でソートされます。これは以下のように計算されます。
(A1 A2 …)
という特定化子リストをもつメソッド a
と
(B1 B2 …)
という特定化子リストをもつメソッド b
とが
あるとします。
An
と Bn
とが異る最小の n を見つけます。n 番目の
引数のクラスをとり、そのクラスの順位リストをチェックします。もし、
その CPL の中で、An
が Bn
より先にくれば、method a
は
メソッド b
より特定化されているということにし、さもなければ、
b
が a
がより特定化されているということにします。
a
および b
のすべての特定化子が、一方は rest 引数
をもち、もう一方はもたないという以外同じであれば、rest 引数をもたない
メソッドのほうがそうでないものより特定化されているとします。
メソッドがソートされたら、最初のメソッドの本体が実引数で呼ばれます。
メソッド本体内部では、特別なローカル変数 next-method
が暗黙裏に
束縛されます。