GNU Info

Info Node: (cl)Customizing Setf

(cl)Customizing Setf


Prev: Modify Macros Up: Generalized Variables
Enter node , (file) or (file)node

Customizing Setf
----------------

Common Lisp defines three macros, `define-modify-macro', `defsetf', and
`define-setf-method', that allow the user to extend generalized
variables in various ways.

 - Special Form: define-modify-macro name arglist function [doc-string]
     This macro defines a "read-modify-write" macro similar to `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.

 - Special Form: defsetf access-fn update-fn
     This is the simpler of two `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)

 - Special Form: defsetf access-fn arglist (store-var) forms...
     This is the second, more complex, form of `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))

 - Special Form: define-setf-method access-fn arglist forms...
     This is the most general way to create new place forms.  When a
     `setf' to ACCESS-FN with arguments described by ARGLIST is
     expanded, the FORMS are evaluated and must return a list of five
     items:

       1. A list of "temporary variables".

       2. A list of "value forms" corresponding to the temporary
          variables above.  The temporary variables will be bound to
          these value forms as the first step of any operation on the
          generalized variable.

       3. A list of exactly one "store variable" (generally obtained
          from a call to `gensym').

       4. A Lisp form which stores the contents of the store variable
          into the generalized variable, assuming the temporaries have
          been bound as described above.

       5. A Lisp form which accesses the contents of the generalized
          variable, assuming the temporaries have been bound.

     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.

 - Function: get-setf-method place &optional env
     This function returns the setf-method for PLACE, by invoking the
     definition previously recorded by `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.


automatically generated by info2www version 1.2.2.9