summaryrefslogtreecommitdiff
path: root/devdocs/elisp/porting-old-advice.html
blob: f36c957a2960c858df9d3515459a1a5f57e2eb60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 <h4 class="subsection">Adapting code using the old defadvice</h4>     <p>A lot of code uses the old <code>defadvice</code> mechanism, which is largely made obsolete by the new <code>advice-add</code>, whose implementation and semantics is significantly simpler. </p> <p>An old piece of advice such as: </p> <div class="example"> <pre class="example">(defadvice previous-line (before next-line-at-end
                                 (&amp;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))))
</pre>
</div> <p>could be translated in the new advice mechanism into a plain function: </p> <div class="example"> <pre class="example">(defun previous-line--next-line-at-end (&amp;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))))
</pre>
</div> <p>Obviously, this does not actually modify <code>previous-line</code>. For that the old advice needed: </p>
<div class="example"> <pre class="example">(ad-activate 'previous-line)
</pre>
</div> <p>whereas the new advice mechanism needs: </p>
<div class="example"> <pre class="example">(advice-add 'previous-line :before #'previous-line--next-line-at-end)
</pre>
</div> <p>Note that <code>ad-activate</code> 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 piece, you needed to <em>enable</em> or <em>disable</em> it with <code>ad-enable-advice</code> and <code>ad-disable-advice</code>. The new mechanism does away with this distinction. </p> <p>Around advice such as: </p> <div class="example"> <pre class="example">(defadvice foo (around foo-around)
  "Ignore case in `foo'."
  (let ((case-fold-search t))
    ad-do-it))
(ad-activate 'foo)
</pre>
</div> <p>could translate into: </p> <div class="example"> <pre class="example">(defun foo--foo-around (orig-fun &amp;rest args)
  "Ignore case in `foo'."
  (let ((case-fold-search t))
    (apply orig-fun args)))
(advice-add 'foo :around #'foo--foo-around)
</pre>
</div> <p>Regarding the advice’s <em>class</em>, note that the new <code>:before</code> is not quite equivalent to the old <code>before</code>, because in the old advice you could modify the function’s arguments (e.g., with <code>ad-set-arg</code>), and that would affect the argument values seen by the original function, whereas in the new <code>:before</code>, modifying an argument via <code>setq</code> in the advice has no effect on the arguments seen by the original function. When porting <code>before</code> advice which relied on this behavior, you’ll need to turn it into new <code>:around</code> or <code>:filter-args</code> advice instead. </p> <p>Similarly old <code>after</code> advice could modify the returned value by changing <code>ad-return-value</code>, whereas new <code>:after</code> advice cannot, so when porting such old <code>after</code> advice, you’ll need to turn it into new <code>:around</code> or <code>:filter-return</code> advice instead. </p><div class="_attribution">
  <p class="_attribution-p">
    Copyright &copy; 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
    <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Porting-Old-Advice.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Porting-Old-Advice.html</a>
  </p>
</div>