Modify Macros
Generalized Variables
Common Lisp defines three macros, define-modify-macro
,
defsetf
, and define-setf-method
, that allow the
user to extend generalized variables in various ways.
incf
and decf
. The macro name is defined
to take a place argument followed by additional arguments
described by arglist. The call
(name place args...)
will be expanded to
(callf func place args...)
which in turn is roughly equivalent to
(setf place (func place args...))
For example:
(define-modify-macro incf (&optional (n 1)) +) (define-modify-macro concatf (&rest args) concat)
Note that &key
is not allowed in arglist, but
&rest
is sufficient to pass keywords on to the function.
Most of the modify macros defined by Common Lisp do not exactly
follow the pattern of define-modify-macro
. For example,
push
takes its arguments in the wrong order, and pop
is completely irregular. You can define these macros ``by hand''
using get-setf-method
, or consult the source file
`cl-macs.el
' to see how to use the internal setf
building blocks.
defsetf
forms. Where
access-fn is the name of a function which accesses a place,
this declares update-fn to be the corresponding store
function. From now on,
(setf (access-fn arg1 arg2 arg3) value)
will be expanded to
(update-fn arg1 arg2 arg3 value)
The update-fn is required to be either a true function, or
a macro which evaluates its arguments in a function-like way. Also,
the update-fn is expected to return value as its result.
Otherwise, the above expansion would not obey the rules for the way
setf
is supposed to behave.
As a special (non-Common-Lisp) extension, a third argument of t
to defsetf
says that the update-fn
's return value is
not suitable, so that the above setf
should be expanded to
something more like
(let ((temp value)) (update-fn arg1 arg2 arg3 temp) temp)
Some examples of the use of defsetf
, drawn from the standard
suite of setf methods, are:
(defsetf car setcar) (defsetf symbol-value set) (defsetf buffer-name rename-buffer t)
defsetf
. It is
rather like defmacro
except for the additional store-var
argument. The forms should return a Lisp form which stores
the value of store-var into the generalized variable formed
by a call to access-fn with arguments described by arglist.
The forms may begin with a string which documents the setf
method (analogous to the doc string that appears at the front of a
function).
For example, the simple form of defsetf
is shorthand for
(defsetf access-fn (&rest args) (store) (append '(update-fn) args (list store)))
The Lisp form that is returned can access the arguments from
arglist and store-var in an unrestricted fashion;
macros like setf
and incf
which invoke this
setf-method will insert temporary variables as needed to make
sure the apparent order of evaluation is preserved.
Another example drawn from the standard package:
(defsetf nth (n x) (store) (list 'setcar (list 'nthcdr n x) store))
setf
to access-fn with arguments described by
arglist is expanded, the forms are evaluated and
must return a list of five items:
gensym
).
This is exactly like the Common Lisp macro of the same name, except that the method returns a list of five values rather than the five values themselves, since Emacs Lisp does not support Common Lisp's notion of multiple return values.
Once again, the forms may begin with a documentation string.
A setf-method should be maximally conservative with regard to
temporary variables. In the setf-methods generated by
defsetf
, the second return value is simply the list of
arguments in the place form, and the first return value is a
list of a corresponding number of temporary variables generated
by gensym
. Macros like setf
and incf
which
use this setf-method will optimize away most temporaries that
turn out to be unnecessary, so there is little reason for the
setf-method itself to optimize.
defsetf
or define-setf-method
. The result is a list of five
values as described above. You can use this function to build
your own incf
-like modify macros. (Actually, it is
better to use the internal functions cl-setf-do-modify
and cl-setf-do-store
, which are a bit easier to use and
which also do a number of optimizations; consult the source
code for the incf
function for a simple example.)
The argument env specifies the ``environment'' to be
passed on to macroexpand
if get-setf-method
should
need to expand a macro in place. It should come from
an &environment
argument to the macro or setf-method
that called get-setf-method
.
See also the source code for the setf-methods for apply
and substring
, each of which works by calling
get-setf-method
on a simpler case, then massaging
the result in various ways.
Modern Common Lisp defines a second, independent way to specify
the setf
behavior of a function, namely ``setf
functions'' whose names are lists (setf name)
rather than symbols. For example, (defun (setf foo) ...)
defines the function that is used when setf
is applied to
foo
. This package does not currently support setf
functions. In particular, it is a compile-time error to use
setf
on a form which has not already been defsetf
'd
or otherwise declared; in newer Common Lisps, this would not be
an error since the function (setf func)
might be
defined later.