Advice On Emacs Advice
1. Introduction
Love it or hate it, lisp advice
is powerful and useful. This
article covers some of the places where advice
can provide a means
of discovering useful behaviors that can then be later codified
without resorting to advice. Advice can also prove to be a powerful
means of experimentation; these experiments can become permanent, e.g., when the
resulting modifications introduced via advice
are only relevant to a small
minority — a good example is package Emacspeak. These are but two
extremes of a continuum and advice
enables many possibilities in
that range.
This article is written in the light of nearly 28 years of Emacspeak
development, a time during which I have learn some useful lessons on
how to use advice safely and program defensively.
This article itself does not take any position in the Advice is evil,
dont use it debate — it is here to help you if you do decide to use
advice
for a given task.
2. Where Advice Can Be Useful
- Temporarily trace a given function —
advice
can display messages on entry and exit to the adviced function. Emacs' own built-in debug-on-entry mostly obviates the need to do this. - You want custom behavior for some command in a package, where
the package author (hasn't yet) provided an appropriate before
or after hook. Implementing the desired behavior as a before
or after advice is a friction-free means of experimenting with
your idea. Once proven useful, the advice-based prototype can be
used to motivate the introduction of the new hook, and once
implemented, you can eliminate the
advice
. - Having implemented a custom behavior, you discover that the author of the package you are extending is unable to incorporate your suggestion. Advice here can provide a light-weight alternative to forking the package in question.
- The modified behavior you wish to implement is relevant to a small minority. You need to advice a large number of functions because the modified behavior you desire requires complete access to the calling context and environment. A good example is generating rich contextual spoken feedback — advice is excellently suited to this task.
3. Advice Tips
These tips are written in terms of defadvice
but apply equally well
to the API introduced in module nadvice
.
- Use
before/after
advice as far as possible, and resort toaround
advice only when you must. - Name all your
advice
fragments consistently. - Do not depend on the argument names used in the function being adviced, instead use ad-get-arg to positionally access the adviced function's arguments.
- Use lexical scoping in all your functions, and be rigorous in declaring any special variables using (cl-declare (special …)) in your code. The byte-compiler is your friend; use this declaration when you see warnings about special variables.
- Except for very simple advice fragments, use a let form inside your advice to bind variables.
- Within your advice, do not depend on any global state that you haven't yourself bound within the let body in your advice.
- If you write
around
advice, ensure that the last form in youradvice
is ad-return-value. Dont modify this value unless you absolutely must. - Make sure to use ad-do-it in your
around
advice so that the original function gets called — except in the very rare cases where you want to entirely bypass the original function. - In the rare case where you have multiple defadvice on the same
function, note that you can specify the order win which these are
called. Use this only when experimenting, and make sure to
clean-up later by combining the advice fragments into a single
call to
defadvice
.
4. Historical Note
- Advice was contributed to Emacs in early 1994 by Hans Chalupsky. I started the Emacspeak project a few months after and am indebted to him — both for his advice implementation and for numerous email exchanges with him at the time as I learnt to use advice.
- I released Emacspeak in April 1995. A few days later I was thrilled to receive a phone call from RMS — where he told me all the reasons why I shouldn't use advice. This was distressing to say the least; I had two choices — abandon Emacspeak using advice, or to ignore his advice. I took the middle-road; I made careful note of all his admonitions and warnings, and the result was to program defensively. Many of the tips listed in the previous section are a direct consequence of keeping an eye out for the various pitfalls he outlined during that phone call.
- I've also garnered useful tips and tricks on the emacs-devel list
over the years from folks like Stefan Mounier — especially as
Emacs transitioned to module
nadvice
in 2014.