emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r116787: * doc/lispref/functions.texi (Advising Func


From: Stefan Monnier
Subject: [Emacs-diffs] trunk r116787: * doc/lispref/functions.texi (Advising Functions): Try and improve the text.
Date: Tue, 18 Mar 2014 01:51:22 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 116787
revision-id: address@hidden
parent: address@hidden
fixes bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16959
committer: Stefan Monnier <address@hidden>
branch nick: trunk
timestamp: Mon 2014-03-17 21:51:12 -0400
message:
  * 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.
modified:
  doc/lispref/ChangeLog          changelog-20091113204419-o5vbwnq5f7feedwu-6155
  doc/lispref/functions.texi     
functions.texi-20091113204419-o5vbwnq5f7feedwu-6182
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
=== modified file 'doc/lispref/ChangeLog'
--- a/doc/lispref/ChangeLog     2014-03-18 01:19:03 +0000
+++ b/doc/lispref/ChangeLog     2014-03-18 01:51:12 +0000
@@ -1,3 +1,13 @@
+2014-03-18  Stefan  <address@hidden>
+
+       * 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  <address@hidden>
 
        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  <address@hidden>
 
@@ -34,12 +43,10 @@
 
 2014-03-09  Martin Rudalics  <address@hidden>
 
-       * 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  <address@hidden>
 
        * 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  <address@hidden>
 
@@ -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  <address@hidden>
 
@@ -349,8 +355,7 @@
 
 2013-12-28  Chong Yidong  <address@hidden>
 
-       * 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  <address@hidden>

=== modified file 'doc/lispref/functions.texi'
--- a/doc/lispref/functions.texi        2014-02-28 10:31:26 +0000
+++ b/doc/lispref/functions.texi        2014-03-18 01:51:12 +0000
@@ -11,23 +11,23 @@
 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 @@
 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 @@
 @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
address@hidden, 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 @address@hidden, 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.
-
-For example, in order to trace the calls to a process filter, you can use:
+  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.
+
+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
address@hidden and @code{advice-remove}).
+
+For example, in order to trace the calls to the process filter of a process
address@hidden, 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 @@
 When you're done with it, you can revert to the untraced behavior with:
 
 @example
-(remove-function (process-filter proc) #'my-tracing-function)
address@hidden 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
address@hidden
-
-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
address@hidden 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.
+(remove-function (process-filter @var{proc}) #'my-tracing-function)
address@hidden example
+
+Similarly, if you want to trace the execution of the function named
address@hidden, you could use:
+
address@hidden
+(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)
address@hidden example
+
+and when you're tired of seeing this output, you can revert to the untraced
+behavior with:
+
address@hidden
+(advice-remove 'display-buffer #'his-tracing-function)
address@hidden 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
 
address@hidden Advising Primitives
address@hidden Primitives to manipulate advice
address@hidden Core Advising Primitives
address@hidden 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
address@hidden  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 @@
 and its properties.
 @end defun
 
address@hidden 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.
address@hidden 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.
-
-  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.
+You could just use @code{add-function} as in:
+
address@hidden
+(add-function :around (symbol-function '@var{fun}) #'his-tracing-function)
address@hidden 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
address@hidden: 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 @@
 and its properties.
 @end defun
 
address@hidden Porting old advices
address@hidden 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:
+
address@hidden
+(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))))
address@hidden example
+
+could be translated in the new advice mechanism into a plain function:
+
address@hidden
+(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))))
address@hidden example
+
+Obviously, this does not actually modify @code{previous-line}.  For that the
+old advice needed:
address@hidden
+(ad-activate 'previous-line)
address@hidden example
+whereas the new advice mechanism needs:
address@hidden
+(advice-add 'previous-line :before #'previous-line--next-line-at-end)
address@hidden 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:
+
address@hidden
+(defadvice foo (around foo-around)
+  "Ignore case in `foo'."
+  (let ((case-fold-search t))
+    ad-do-it))
+(ad-activate 'foo)
address@hidden example
+
+could translate into:
+
address@hidden
+(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)
address@hidden 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
address@hidden: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
address@hidden:around} or @code{:filter-return} advice instead.
+
 @node Obsolete Functions
 @section Declaring Functions Obsolete
 @cindex obsolete functions

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2014-03-18 01:13:00 +0000
+++ b/lisp/ChangeLog    2014-03-18 01:51:12 +0000
@@ -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)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]