Introduction
Welcome to the next lesson in our journey to extend Emacs. In our previous lesson, you learned how to use hooks to execute your own code in response to specific events, like a major mode starting. This is a powerful way to automate your environment. For example, you created a function to set up a comfortable writing environment and hooked it into org-mode.
Hooks are excellent for running code alongside Emacs's normal operations. But what if you need to alter the very behavior of an existing function? For instance, what if you wanted every file save command to also create a timestamped backup, or you wanted to change how Emacs splits windows? Redefining the entire original function is an option, but it's messy and difficult to maintain.
This lesson addresses that exact challenge, focusing on the learning outcome: Explain how advice modifies existing functions without altering their source code. We will explore "advice," a core Elisp concept for cleanly and modularly augmenting the functionality of any existing function. This is one of the most powerful customization tools in your Emacs toolkit.
1. What is Advice and Why Use It?
At its core, advice is a mechanism for "wrapping" an existing function with your own code. Instead of completely replacing a function, you add pieces of logic that run before, after, or even around the original function call.
This is a much cleaner approach than bluntly redefining a function. Let's start by reading the official documentation's introduction to this idea.
Advising Functions (GNU Emacs Lisp Reference Manual)
The GNU Emacs Lisp Reference Manual provides a concise explanation of why advice is a superior method for modifying functions.
Please read the first three paragraphs, starting from 'When you need to modify a function...' and ending with '...advising the function'. Pay close attention to the contrast between 'blunt' methods like defun and the 'cleaner method' of advice.
As the manual states, methods like redefining a function with defun are "too blunt" because they completely discard the original function. Using advice offers several key advantages:
- Modularity: Your changes are kept separate from the original code. You don't need to copy and paste the original function's source into your configuration just to make a small tweak.
- Maintainability: When you update Emacs or a package, the original function might be improved or fixed. If you've redefined it, you won't get those updates. Advice, however, applies your changes to the new version of the function automatically.
- Reversibility: Advice can be easily added and removed programmatically. This makes it simple to turn your customizations on or off, which is much harder if you've completely redefined a function.
Given your background in creative direction, you can think of it like this: Advising a function is like giving stage directions to an actor. The original script (the function's source code) remains untouched. You are simply adding notes that modify the performance:
- "Before you say your line, pause and look at the audience."
- "After you say your line, exit stage left."
- "Instead of saying your line, just perform this gesture."
This leaves the original work intact while allowing you to augment it in powerful ways.
2. The Anatomy of Advice
The modern advice system in Emacs, introduced in 2012, is centered around the advice-add function. Let's look at the basic components.
The blog post 'Some Emacs advice' provides a good, high-level overview of the history and basic usage of advice.
Please read the sections 'Advising Emacs' and 'History'. Note the distinction between the old defadvice and the newer, recommended advice-add system. You don't need to worry about the code examples for now.
As the article explains, advising a function involves three key elements:
- The Target Function: The original function you want to modify (e.g.,
save-buffer). - The Advising Function: The function you write that contains the new behavior.
- The Combinator: A keyword that specifies how your advising function should be combined with the target function.
The most common combinators are :before, :after, and :around. These keywords are the "stage directions" that tell Emacs when to run your code relative to the original function.

3. Types of Advice: A Conceptual Overview
Let's briefly define what the main combinators do. You will get hands-on experience with them in the next lesson, but for now, we'll focus on the concepts.
- :before: Your advising function runs before the original function is called. It receives the same arguments as the original, but its return value is ignored. This is useful for setup tasks or checks that need to happen before the main action.
- :after: Your advising function runs after the original function completes. This is useful for cleanup tasks or for actions that depend on the result of the original function.
- :around: This is the most powerful combinator. Your advising function wraps the original function. It receives the original function itself as an argument, along with all the other arguments. Your code is now in complete control: it can decide whether to call the original function, what arguments to pass it, and what to do with its return value.
4. A Concrete Example: Tracing a Function
To see how this works in practice, let's look at a classic use case for advice: tracing the execution of a function to understand how it's being used. The display-buffer function, for example, is a complex part of Emacs responsible for deciding how and where new windows appear. Let's imagine we want to see exactly how it's being called.
The GNU Manual provides a perfect example of this using :around advice.
Advising Functions (GNU Emacs Lisp Reference Manual)
Let's examine a practical example from the GNU Emacs Lisp Reference Manual. This code adds tracing messages before and after calls to display-buffer.
Focus on the code block that starts with (defun his-tracing-function ...) and the text explaining it. We will break it down together below.
Let's dissect the code from the manual:
;; 1. Define the advising function
(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))
;; 2. Add the advice
(advice-add 'display-buffer :around #'his-tracing-function)
Here’s what’s happening, step by step:
his-tracing-function: This is our custom advising function. Because it will be used with:aroundadvice, its first argument,orig-fun, will be the originaldisplay-bufferfunction itself. The&rest argscollects all of the original arguments into a list namedargs.(message "display-buffer called..."): This is our:beforeaction. It prints a message showing us what argumentsdisplay-bufferwas called with.(apply orig-fun args): This is the critical part. We are now calling the original function (orig-fun) that was passed to us, applying the original arguments (args) to it. We store its return value in the variableres.(message "display-buffer returned..."): This is our:afteraction. It prints a message showing what the original function returned.res: The advising function returns the original function's result, ensuring the overall behavior is preserved.advice-add: This call connects everything. It tells Emacs: "Whendisplay-bufferis called, runhis-tracing-functionaround it."
With this advice active, every time anything in Emacs tries to display a new buffer, you will see log messages telling you exactly what is happening, all without ever touching the source code of display-buffer. To stop the tracing, you would simply call (advice-remove 'display-buffer #'his-tracing-function).
Conclusion
In this lesson, you have learned the concept of function advice in Emacs Lisp. You now understand that it provides a clean, modular, and maintainable way to modify the behavior of existing functions without directly altering their source code.
Key Takeaways:
- Advice is a mechanism for wrapping existing functions with new code.
- It is a cleaner and more robust alternative to function redefinition.
- The modern system uses
advice-addto connect an advising function to a target function. - Combinators like
:before,:after, and:aroundspecify how the new and old code should interact. :aroundadvice is the most powerful, giving your code full control over the execution of the original function.
Preview of the Next Lesson
You now have a solid conceptual understanding of what advice is and why it's so useful. In the next lesson, we will move from theory to practice. You will learn to use advice-add with the :before, :after, and :around combinators to solve practical customization problems, further tailoring Emacs to your specific workflow.