次: , 前: Preactivation, 上: Advising Functions


16.8 アドバイスからの引数の参照

アドバイス断片の本体からアドバイスする関数の引数を参照する もっとも簡単な方法は、関数定義で用いているものと同じ名前を使うことです。 これには、元関数の引数の変数名を知る必要があります。

多くの場合、この単純な方法で十分ですが、欠点もあります。 アドバイス内に引数名を直接書き込むために、堅牢ではありません。 関数の元定義が変更されると、アドバイスは動作しません。

他の方法は、アドバイスそのものに引数リストを指定することです。 これは関数の元定義の引数名を知る必要はありませんが、制約もあります。 関数に対するすべてのアドバイスで同一の引数リストを使う必要があります。 なぜなら、すべてのアドバイスに実際に使われる引数リストは、 当該関数のアドバイス断片の最初のものだからです。

より堅牢な方法は、活性にするときに、 つまり、アドバイスを結合した定義を作成するときに 適切なフォームに展開されるマクロを使うことです。 参照用マクロは、関数の引数変数への実引数の分配方法に依存しない 実引数の位置で参照します。 Emacs Lispにおいては、引数の意味は引数リスト内での位置で決まるため、 これは堅牢です。

— マクロ: ad-get-arg position

位置positionにある実引数を返す。

— マクロ: ad-get-args position

位置positionから始まる実引数のリストを返す。

— マクロ: ad-set-arg position value

位置positionにある実引数の値を設定する。

— マクロ: ad-set-args position value-list

位置positionから始まる実引数のリストにvalue-listを設定する。

例を示します。 関数fooの定義はつぎのとおりであり、

     (defun foo (x y &optional z &rest r) ...)

つぎのように呼ばれるとします。

     (foo 0 1 2 3 4 5 6)

そうすると、fooの本体では、 xは0、yは1、zは2、r(3 4 5 6)です。 このとき、ad-get-argad-get-argsは、つぎの値を返します。

     (ad-get-arg 0) => 0
     (ad-get-arg 1) => 1
     (ad-get-arg 2) => 2
     (ad-get-arg 3) => 3
     (ad-get-args 2) => (2 3 4 5 6)
     (ad-get-args 4) => (4 5 6)

この例では、引数に値を設定できます。

     (ad-set-arg 5 "five")

の効果は、6番目の引数を"five"に変更します。 fooの本体を実行するまえにこのアドバイスが実行されると、 本体内ではr(3 4 "five" 6)になります。

つぎは引数リストを変更する例です。

     (ad-set-args 0 '(5 4 3 2 1 0))

fooの本体を実行するまえにこのアドバイスが実行されると、 fooの本体内では、 xは5、yは4、zは3、r(2 1 0)になります。

これらの引数参照は、実際にはLispマクロとしての実装ではありません。 アドバイス機構で特別に実装してあります。