Go to the first, previous, next, last section, table of contents.


Argument Access in Advice

The simplest way to access the arguments of an advised function in the body of a piece of advice is to use the same names that the function definition uses. To do this, you need to know the names of the argument variables of the original function.

While this simple method is sufficient in many cases, it has a disadvantage: it is not robust, because it hard-codes the argument names into the advice. If the definition of the original function changes, the advice might break.

Another method is to specify an argument list in the advice itself. This avoids the need to know the original function definition's argument names, but it has a limitation: all the advice on any particular function must use the same argument list, because the argument list actually used for all the advice comes from the first piece of advice for that function.

A more robust method is to use macros that are translated into the proper access forms at activation time, i.e., when constructing the advised definition. Access macros access actual arguments by position regardless of how these actual arguments get distributed onto the argument variables of a function. This is robust because in Emacs Lisp the meaning of an argument is strictly determined by its position in the argument list.

Macro: ad-get-arg position
This returns the actual argument that was supplied at position.

Macro: ad-get-args position
This returns the list of actual arguments supplied starting at position.

Macro: ad-set-arg position value
This sets the value of the actual argument at position to value

Macro: ad-set-args position value-list
This sets the list of actual arguments starting at position to value-list.

Now an example. Suppose the function foo is defined as

(defun foo (x y &optional z &rest r) ...)

and is then called with

(foo 0 1 2 3 4 5 6)

which means that x is 0, y is 1, z is 2 and r is (3 4 5 6) within the body of foo. Here is what ad-get-arg and ad-get-args return in this case:

(ad-get-arg 0) => 0
(ad-get-arg 1) => 1
(ad-get-arg 2) => 2
(ad-get-arg 3) => 3
(ad-get-args 2) => (2 3 4 5 6)
(ad-get-args 4) => (4 5 6)

Setting arguments also makes sense in this example:

(ad-set-arg 5 "five")

has the effect of changing the sixth argument to "five". If this happens in advice executed before the body of foo is run, then r will be (3 4 "five" 6) within that body.

Here is an example of setting a tail of the argument list:

(ad-set-args 0 '(5 4 3 2 1 0))

If this happens in advice executed before the body of foo is run, then within that body, x will be 5, y will be 4, z will be 3, and r will be (2 1 0) inside the body of foo.

These argument constructs are not really implemented as Lisp macros. Instead they are implemented specially by the advice mechanism.


Go to the first, previous, next, last section, table of contents.