1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-07 12:59:26 +00:00

* doc/lispref/functions.texi (Advising Functions): Try and improve the text.

Add example use of advice-add.
(Core Advising Primitives): Rename.  Explain handling of interactive
specs, including advice-eval-interactive-spec.
(Advising Named Functions): Try and better explain the difference with
add-function.
(Porting old advices): New node.

Fixes: debbugs:16959
This commit is contained in:
Stefan Monnier 2014-03-17 21:51:12 -04:00
parent 09b73f0820
commit 6c187ef5a5
3 changed files with 212 additions and 72 deletions

View File

@ -1,3 +1,13 @@
2014-03-18 Stefan <monnier@iro.umontreal.ca>
* functions.texi (Advising Functions): Try and improve the text.
Add example use of advice-add (bug#16959).
(Core Advising Primitives): Rename. Explain handling of interactive
specs, including advice-eval-interactive-spec.
(Advising Named Functions): Try and better explain the difference with
add-function.
(Porting old advices): New node.
2014-03-18 Paul Eggert <eggert@cs.ucla.edu>
Style fixes for floating-point doc.
@ -16,8 +26,7 @@
* display.texi (Temporary Displays): Rewrite descriptions of
`with-output-to-temp-buffer' and `with-temp-buffer-window'.
* help.texi (Help Functions): Rewrite description of
`with-help-window'.
* help.texi (Help Functions): Rewrite description of `with-help-window'.
2014-03-15 Dmitry Gutov <dgutov@yandex.ru>
@ -34,12 +43,10 @@
2014-03-09 Martin Rudalics <rudalics@gmx.at>
* elisp.texi (Top): Rename section "Width" to "Size of Displayed
Text".
* elisp.texi (Top): Rename section "Width" to "Size of Displayed Text".
* text.texi (Primitive Indent):
* strings.texi (String Basics):
* sequences.texi (Sequence Functions): Update references
accordingly.
* sequences.texi (Sequence Functions): Update references accordingly.
* display.texi (Size of Displayed Text): Rename section from
"Width". Add description for `window-text-pixel-size'.
(Window Dividers): Reword description of window dividers.
@ -64,12 +71,12 @@
2014-03-06 Martin Rudalics <rudalics@gmx.at>
* frames.texi (Size and Position): Rewrite entries for
`fit-frame-to-buffer' and `fit-frame-to-buffer-margins'. Add
description for `fit-frame-to-buffer-sizes'.
`fit-frame-to-buffer' and `fit-frame-to-buffer-margins'.
Add description for `fit-frame-to-buffer-sizes'.
* windows.texi (Resizing Windows): Add descriptions for
pixelwise resizing. Add entries for `window-resize-pixelwise'
and `fit-window-to-buffer-horizontally'. Rewrite
`fit-window-to-buffer' entry.
and `fit-window-to-buffer-horizontally'.
Rewrite `fit-window-to-buffer' entry.
2014-03-06 Xue Fuqiao <xfq@gnu.org>
@ -93,8 +100,7 @@
`window-min-height' and `window-min-width'. Remove description
of `window-size-fixed-p' moving part of it to that of
`window-size-fixed'.
(Resizing Windows): Mention dividers when talking about minimum
sizes.
(Resizing Windows): Mention dividers when talking about minimum sizes.
2014-03-05 Glenn Morris <rgm@gnu.org>
@ -349,8 +355,7 @@
2013-12-28 Chong Yidong <cyd@gnu.org>
* modes.texi (Auto Major Mode): Document interpreter-mode-alist
change.
* modes.texi (Auto Major Mode): Document interpreter-mode-alist change.
* buffers.texi (Modification Time): Document visited-file-modtime
change.
@ -387,8 +392,7 @@
* display.texi (Font Selection): Tweak example.
* commands.texi (Event Input Misc): Document new arg to
input-pending-p.
* commands.texi (Event Input Misc): Document new arg to input-pending-p.
* nonascii.texi (Specifying Coding Systems): Don't refer to
emacs-mule-dos.
@ -633,7 +637,8 @@
* display.texi (Showing Images): Add an index for image-size.
Use @code instead of @var for a normal variable.
(Multi-Frame Images): Improve indexing.
(Button Buffer Commands): Use @code instead of @var for a normal variable.
(Button Buffer Commands): Use @code instead of @var for a normal
variable.
(Abstract Display): Explain the meaning of Ewoc.
2013-10-27 Xue Fuqiao <xfq.free@gmail.com>

View File

@ -11,23 +11,23 @@ explains what functions are, how they accept arguments, and how to
define them.
@menu
* What Is a Function:: Lisp functions vs. primitives; terminology.
* Lambda Expressions:: How functions are expressed as Lisp objects.
* Function Names:: A symbol can serve as the name of a function.
* Defining Functions:: Lisp expressions for defining functions.
* Calling Functions:: How to use an existing function.
* Mapping Functions:: Applying a function to each element of a list, etc.
* Anonymous Functions:: Lambda expressions are functions with no names.
* Function Cells:: Accessing or setting the function definition
* What Is a Function:: Lisp functions vs. primitives; terminology.
* Lambda Expressions:: How functions are expressed as Lisp objects.
* Function Names:: A symbol can serve as the name of a function.
* Defining Functions:: Lisp expressions for defining functions.
* Calling Functions:: How to use an existing function.
* Mapping Functions:: Applying a function to each element of a list, etc.
* Anonymous Functions:: Lambda expressions are functions with no names.
* Function Cells:: Accessing or setting the function definition
of a symbol.
* Closures:: Functions that enclose a lexical environment.
* Advising Functions:: Adding to the definition of a function.
* Obsolete Functions:: Declaring functions obsolete.
* Inline Functions:: Functions that the compiler will expand inline.
* Declare Form:: Adding additional information about a function.
* Declaring Functions:: Telling the compiler that a function is defined.
* Function Safety:: Determining whether a function is safe to call.
* Related Topics:: Cross-references to specific Lisp primitives
* Closures:: Functions that enclose a lexical environment.
* Advising Functions:: Adding to the definition of a function.
* Obsolete Functions:: Declaring functions obsolete.
* Inline Functions:: Functions that the compiler will expand inline.
* Declare Form:: Adding additional information about a function.
* Declaring Functions:: Telling the compiler that a function is defined.
* Function Safety:: Determining whether a function is safe to call.
* Related Topics:: Cross-references to specific Lisp primitives
that have a special bearing on how functions work.
@end menu
@ -208,10 +208,10 @@ Before going into these details, the following subsections describe
the components of a lambda expression and what they do.
@menu
* Lambda Components:: The parts of a lambda expression.
* Simple Lambda:: A simple example.
* Argument List:: Details and special features of argument lists.
* Function Documentation:: How to put documentation in a function.
* Lambda Components:: The parts of a lambda expression.
* Simple Lambda:: A simple example.
* Argument List:: Details and special features of argument lists.
* Function Documentation:: How to put documentation in a function.
@end menu
@node Lambda Components
@ -1142,19 +1142,32 @@ examining or altering the structure of closure objects.
@cindex advising functions
@cindex piece of advice
Any variable or object field which holds a function can be modified with the
appropriate setter function, such as @code{set-process-filter}, @code{fset}, or
@code{setq}, but those can be too blunt, completely throwing away the
When you need to modify a function defined in another library, or when you need
to modify a hook like @code{@var{foo}-function}, a process filter, or basically
any variable or object field which holds a function value, you can use the
appropriate setter function, such as @code{fset} or @code{defun} for named
functions, @code{setq} for hook variables, or @code{set-process-filter} for
process filters, but those are often too blunt, completely throwing away the
previous value.
In order to modify such hooks in a more controlled way, Emacs provides the
macros @code{add-function} and @code{remove-function}, which let you modify the
existing function value by composing it with another function.
The @dfn{advice} feature lets you add to the existing definition of
a function, by @dfn{advising the function}. This is a cleaner method
than redefining the whole function.
For example, in order to trace the calls to a process filter, you can use:
Emacs's advice system provides two sets of primitives for that: the core set,
for function values held in variables and object fields (with the corresponding
primitives being @code{add-function} and @code{remove-function}) and another
set layered on top of it for named functions (with the main primitives being
@code{advice-add} and @code{advice-remove}).
For example, in order to trace the calls to the process filter of a process
@var{proc}, you could use:
@example
(add-function :before (process-filter proc) #'my-tracing-function)
(defun my-tracing-function (proc string)
(message "Proc %S received %S" proc string))
(add-function :before (process-filter @var{proc}) #'my-tracing-function)
@end example
This will cause the process's output to be passed first to
@ -1162,33 +1175,55 @@ This will cause the process's output to be passed first to
When you're done with it, you can revert to the untraced behavior with:
@example
(remove-function (process-filter proc) #'my-tracing-function)
(remove-function (process-filter @var{proc}) #'my-tracing-function)
@end example
The argument @code{:before} specifies how the two functions are composed, since
there are many different ways to do it. The added function is also called an
@emph{advice}.
Similarly, if you want to trace the execution of the function named
@code{display-buffer}, you could use:
The function cell of a symbol can be manipulated similarly, but since it can
contain other things than a plain function, you have to use @code{advice-add}
and @code{advice-remove} instead, which
@c use @code{add-function} and @code{remove-function} internally, but
know how to handle cases such as when the function cell holds a macro rather
than function, or when the function is autoloaded so the advice's activation
needs to be postponed.
@example
(defun his-tracing-function (orig-fun &rest args)
(message "display-buffer called with args %S" args)
(let ((res (apply orig-fun args)))
(message "display-buffer returned %S" res)
res))
(advice-add 'display-buffer :around #'his-tracing-function)
@end example
and when you're tired of seeing this output, you can revert to the untraced
behavior with:
@example
(advice-remove 'display-buffer #'his-tracing-function)
@end example
The arguments @code{:before} and @code{:above} used in the above examples
specify how the two functions are composed, since there are many different
ways to do it. The added function is also called an @emph{advice}.
@menu
* Advising Primitives:: Primitives to Manipulate Advices
* Advising Named Functions:: Advising Named Functions
* Core Advising Primitives:: Primitives to Manipulate Advices
* Advising Named Functions:: Advising Named Functions
* Porting old advices:: Adapting code using the old defadvice
@end menu
@node Advising Primitives
@subsection Primitives to manipulate advice
@node Core Advising Primitives
@subsection Primitives to manipulate advices
@defmac add-function where place function &optional props
This macro is the handy way to add the advice @var{function} to the function
stored in @var{place} (@pxref{Generalized Variables}).
If @var{function} is not interactive, then the combined function will inherit
the interactive spec, if any, of the original function. Else, the combined
function will be interactive and will use the interactive spec of
@var{function}. One exception: if the interactive spec of @var{function}
is a function (rather than an expression or a string), then the interactive
spec of the combined function will be a call to that function with as sole
argument the interactive spec of the original function. To interpret the spec
received as argument, use @code{advice-eval-interactive-spec}.
@var{where} determines how @var{function} is composed with the
existing function. It can be one of the following:
@ -1340,21 +1375,39 @@ Call the function @var{f} for every advice that was added to
and its properties.
@end defun
@defun advice-eval-interactive-spec spec
Evaluate the interactive @var{spec} just like an interactive call to a function
with such a spec would, and then return the corresponding list of arguments
that was built. E.g. @code{(advice-eval-interactive-spec "r\nP")} will
return a list of three elements, containing the boundaries of the region and
the current prefix argument.
@end defun
@node Advising Named Functions
@subsection Advising Named Functions
A common use of advice is for named functions and macros.
Since @code{add-function} does not know how to deal with macros and
autoloaded functions, Emacs provides a separate set of functions to
manipulate pieces of advice applied to named functions.
You could just use @code{add-function} as in:
Advice can be useful for altering the behavior of an existing
function without having to redefine the whole function. However, it
can be a source of bugs, since existing callers to the function may
assume the old behavior, and work incorrectly when the behavior is
changed by advice. Advice can also cause confusion in debugging, if
the person doing the debugging does not notice or remember that the
function has been modified by advice.
@example
(add-function :around (symbol-function '@var{fun}) #'his-tracing-function)
@end example
But you should use @code{advice-add} and @code{advice-remove} for that
instead. This separate set of functions to manipulate pieces of advice applied
to named functions, offers the following extra features compared to
@code{add-function}: they know how to deal with macros and autoloaded
functions, they let @code{describe-function} preserve the original docstring as
well as document the added advice, and they let you add and remove advices
before a function is even defined.
@code{advice-add} can be useful for altering the behavior of existing calls
to an existing function without having to redefine the whole function.
However, it can be a source of bugs, since existing callers to the function may
assume the old behavior, and work incorrectly when the behavior is changed by
advice. Advice can also cause confusion in debugging, if the person doing the
debugging does not notice or remember that the function has been modified
by advice.
For these reasons, advice should be reserved for the cases where you
cannot modify a function's behavior in any other way. If it is
@ -1400,6 +1453,88 @@ Call @var{function} for every advice that was added to the named function
and its properties.
@end defun
@node Porting old advices
@subsection Adapting code using the old defadvice
A lot of code uses the old @code{defadvice} mechanism, which is largely made
obsolete by the new @code{advice-add}, whose implementation and semantics is
significantly simpler.
An old advice such as:
@example
(defadvice previous-line (before next-line-at-end
(&optional arg try-vscroll))
"Insert an empty line when moving up from the top line."
(if (and next-line-add-newlines (= arg 1)
(save-excursion (beginning-of-line) (bobp)))
(progn
(beginning-of-line)
(newline))))
@end example
could be translated in the new advice mechanism into a plain function:
@example
(defun previous-line--next-line-at-end (&optional arg try-vscroll)
"Insert an empty line when moving up from the top line."
(if (and next-line-add-newlines (= arg 1)
(save-excursion (beginning-of-line) (bobp)))
(progn
(beginning-of-line)
(newline))))
@end example
Obviously, this does not actually modify @code{previous-line}. For that the
old advice needed:
@example
(ad-activate 'previous-line)
@end example
whereas the new advice mechanism needs:
@example
(advice-add 'previous-line :before #'previous-line--next-line-at-end)
@end example
Note that @code{ad-activate} had a global effect: it activated all pieces of
advice enabled for that specified function. If you wanted to only activate or
deactivate a particular advice, you needed to @emph{enable} or @emph{disable}
that advice with @code{ad-enable-advice} and @code{ad-disable-advice}.
The new mechanism does away with this distinction.
An around advice such as:
@example
(defadvice foo (around foo-around)
"Ignore case in `foo'."
(let ((case-fold-search t))
ad-do-it))
(ad-activate 'foo)
@end example
could translate into:
@example
(defun foo--foo-around (orig-fun &rest args)
"Ignore case in `foo'."
(let ((case-fold-search t))
(apply orig-fun args)))
(advice-add 'foo :around #'foo--foo-around)
@end example
Regarding the advice's @emph{class}, note that the new @code{:before} is not
quite equivalent to the old @code{before}, because in the old advice you could
modify the function's arguments (e.g., with @code{ad-set-arg}), and that would
affect the argument values seen by the original function, whereas in the new
@code{:before}, modifying an argument via @code{setq} in the advice has no
effect on the arguments seen by the original function.
When porting a @code{before} advice which relied on this behavior, you'll need
to turn it into a new @code{:around} or @code{:filter-args} advice instead.
Similarly an old @code{after} advice could modify the returned value by
changing @code{ad-return-value}, whereas a new @code{:after} advice cannot, so
when porting such an old @code{after} advice, you'll need to turn it into a new
@code{:around} or @code{:filter-return} advice instead.
@node Obsolete Functions
@section Declaring Functions Obsolete
@cindex obsolete functions

View File

@ -27,8 +27,8 @@
* newcomment.el (comment-beginning): If `comment-start-skip'
doesn't match, move back one char and try again. (Bug#16971)
* emacs-lisp/lisp-mode.el (lisp-mode-variables): Set
`comment-use-syntax' to t to avoid the unnecessary runtime check.
* emacs-lisp/lisp-mode.el (lisp-mode-variables):
Set `comment-use-syntax' to t to avoid the unnecessary runtime check.
Set `comment-start-skip' to a simpler value that doesn't try to
check if the semicolon is escaped (this is handled by
`syntax-ppss' now). (Bug#16971)