アドバイスの一般的な用途は、名前付き関数やマクロです。次のように add-function
をそのまま使用することもできます:
(add-function :around (symbol-function 'fun) #'his-tracing-function)
ただし、その場合は代わりに advice-add と advice-remove
を使用してください。名前付き関数に適用されるアドバイスの一部を操作するためのこの独立した関数群は、add-function
と比較して以下のような追加機能を備えています。マクロやオートロードされた関数の扱い方を把握している点、describe-function が元の docstring
を保持しつつ追加したアドバイスを文書化できる点、そして関数が定義される前にアドバイスの一部を追加・削除できる点です。
advice-add
は、関数全体を再定義することなく、既存の関数への既存の呼び出しの挙動を変更する際に有用です。しかし、関数への既存の呼び出し元が従来の挙動を前提としている場合、advice
によって挙動が変更されると正しく動作しなくなるため、バグの原因となる可能性があります。また、デバッグ担当者が advice
によって関数が変更されたことに気づかなかったり覚えていなかったりすると、デバッグ時に混乱を招く恐れもあります。
なお、問題の原因はアドバイスそのものではなく、名前付き関数を変更するという行為にある点に注意してください。fset、defalias、cl-letfといった低レベルのプリミティブを介して名前付き関数を変更することは、さらに問題があります。そうした観点から見れば、アドバイスは変更履歴を追跡できるため、変更内容を一覧表示したり元に戻したりすることができ、名前付き関数を変更するにはより優れた方法と言えます。
名前付き関数の変更は、他の方法ではEmacsの動作を変更できない場合に限定すべきです。フックを用いて同様のことを実現できる場合は、そちらの方が好ましいでしょう(フックを参照)。単に特定のキーの動作を変更したいだけであれば、新しいコマンドを作成し、元のコマンドのキーバインドを新しい方に再割り当てする方が適切かもしれません(コマンドの再割り当てを参照)。
リリースして他者が利用するためのコードを書く際は、その中にアドバイスを含めないようにしてください。アドバイスを記述したい関数にそのためのフックがない場合は、適切なフックの追加についてEmacsの開発者に相談してください。特に、Emacs自身のソースファイルにおいて、Emacsの関数にアドバイスを記述すべきではありません。(現在、この慣習にはいくつかの例外がありますが、それらの是正を目指しています。)一般的に、bar が foo にアドバイスを記述するよりも、foo で新しいフックを作成し、bar
でそのフックを利用する方がすっきりします。
特殊フォーム(特殊フォームを参照)にアドバイスを付与することはできませんが、マクロには関数とほぼ同様の方法でアドバイスを付与できます。もちろん、これは既にマクロ展開済みのコードには影響しないため、マクロが展開される前にアドバイスがインストールされていることを確認する必要があります。
プリミティブ(関数とは何か?を参照)にアドバイスを与えることは可能ですが、通常、2つの理由からそうすべきではありません。第一に、一部のプリミティブはアドバイス機構によって使用されており、それらにアドバイスを与えると無限再帰を引き起こす可能性があります。第二に、多くのプリミティブはCから直接呼び出されており、こうした呼び出しはアドバイスを無視します。その結果、(Lispコードから発生する)一部の呼び出しはアドバイスに従い、他の呼び出し(Cコードから)は従わないという、混乱を招く状況に陥ります。
このマクロはアドバイスを定義し、symbol という名前の関数に追加します。name が nil でない場合、そのアドバイスは symbol@name という名前になり、name
という名前で登録されます。そうでない場合、そのアドバイスは匿名となります。その他の引数に関する説明については、advice-add を参照してください。
名前付き関数 symbol にアドバイス function
を追加します。where と props は add-function と同様の意味を持ちます(アドバイスを操作するためのプリミティブ を参照)。
指定された関数 symbol からアドバイス function を削除します。function はアドバイスの一部の
name である場合もあります。対話的に呼び出された場合は、アドバイス対象の function と削除対象のアドバイスの両方をプロンプトで指定してください。
アドバイス function が既に指定された関数 symbol に含まれている場合は、non-nil
を返します。function は、アドバイスの一部の name となることもあります。
指定された関数 symbol に追加された各アドバイスに対して function を呼び出します。function には、アドバイス関数とそのプロパティという2つの引数が渡されます。