アドバイスは名前つき関数やマクロにたいして使用するのが一般的な使い方です。これは単にadd-function
を使用して以下のように行うことができます:
(add-function :around (symbol-function 'fun) #'his-tracing-function)
しかしかわりにadvice-add
とadvice-remove
を使うべきです。この異なる関数セットは名前つき関数に適用されるアドバイスを操作するためのもので、add-function
と比較して以下の追加機能があります。まずこれらはマクロとオートロードされた関数を扱う方法を知っています。次にdescribe-function
にたいして追加されたアドバイスと同様に、元のドキュメント文字列を維持します。さらに関数が定義される前でも、アドバイスの追加と削除ができます。
既存の関数全体を再定義せずに既存の呼び出しを変更するために、advice-add
が有用になります。しかしその関数の既存の呼び出し元は古い振る舞いを前提としているかもしれず、アドバイスによりその振る舞いが変更されたときに正しく機能しないかもしれないので、バグの原因になり得ます。デバッグを行う人はその関数がアドバイスにより変更されたことに気づかなかったり失念していたりすると、アドバイスはデバッグでの混乱の原因になる可能性もあります。
問題はアドバイス自体ではなく、名前つき関数への変更行為であることに注意してください。fset
、defalias
、cl-letf
のような低レベルのプリミティブを通じて名前つき関数を変更すれば、さらに問題が起こるかもしれません。この観点からアドバイスは変更を追跡して、変更をリストしたりアンドゥできるので、名前つき関数を変更するにはよりよい方法といえるでしょう。
名前つき関数への変更は、他の方法ではEmacsの振る舞いを変更できないような場合に備えるために控えるべきです。フックを通じて同じことが行えるならフック(フックを参照)の使用が望ましい方法です。特定のキーが行う何かを変更したいだけなら、新しいコマンドを記述して、古いコマンドのキーバインドを新しいコマンドにリマップ(コマンドのリマップを参照)するのが、おそらくより優れた方法です。
他の人が使用するリリース用のコードを記述する場合には、アドバイスを含めることを避けるよう試みてください。アドバイスしたい関数にその処理を行うフックがなければ、適切なフックの追加についてEmacs開発者に相談してください。特にEmacs自身のソースファイルでは、Emacs関数にアドバイスを配置するべきではありません(現在のところこの慣習にたいするいくつかの例外があるが修正する予定)。一般的にはfoo
にアドバイスとしてbar
を配置するよりも、foo
内に新たなフックを作成してbar
にそのフックを使用させるほうが明快です。
スペシャルフォーム(スペシャルフォームを参照)はアドバイスできませんが、マクロは関数と同じ方法でアドバイスできます。もちろんこれはすでにマクロ展開されたコードには影響しないため、マクロ展開前にアドバイスが確実にインストールされる必要があります。
プリミティブ(関数とは?を参照)にアドバイスするのは可能ですが、2つの理由により通常は行うべきではありません。1つ目の理由はいくつかのプリミティブがアドバイスのメカニズム内で使用されているため、それらにたいしてアドバイスを行うと無限再帰が発生するからです。2つ目の理由は多くのプリミティブがCから直接呼び出されていて、そのような呼び出しはアドバイスを無視するからです。したがってプリミティブにたいしてアドバイスの使用を控えることにより、ある呼び出しはアドバイスにしたがい(Lispコードから呼びだされたため)、他の呼び出しではアドバイスにしたがわない(Cコードから呼び出されたため)という混乱した状況を解決できます。
このマクロはアドバイスを定義してsymbolという名前の関数に追加する。nameが非nil
ならそのアドバイスの名前はsymbol@name
となり、nameという名前でインストールされる。それ以外の場合にはアドバイスは無名。他の引数についての説明はadvice-add
を参照のこと。
名前つき関数symbolにアドバイスfunctionを追加する。whereとpropsはadd-function
(アドバイスを操作するためのプリミティブを参照)のときと同じ意味をもつ。
名前つき関数symbolからアドバイスfunctionを取り除く。functionにアドバイスのname
を指定することもできる。インタラクティブに呼び出されるとアドバイスされたfunction、削除するアドバイスの両方の入力を求める。
名前つき関数symbol内にすでにアドバイスfunctionがあれば非nil
をリターンする。functionにアドバイスのname
を指定することもできる。
名前つき関数symbolにすでに追加されたすべての関数にたいしてfunctionを呼び出す。functionはアドバイス関数とそのプロパティという2つの引数で呼び出される。