diff options
Diffstat (limited to 'doc/lispref/functions.texi')
-rw-r--r-- | doc/lispref/functions.texi | 180 |
1 files changed, 172 insertions, 8 deletions
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index a70364c3cb5..8e8cc5fd9c0 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -22,6 +22,7 @@ define them. * Function Cells:: Accessing or setting the function definition of a symbol. * Closures:: Functions that enclose a lexical environment. +* OClosures:: Function objects * Advising Functions:: Adding to the definition of a function. * Obsolete Functions:: Declaring functions obsolete. * Inline Functions:: Functions that the compiler will expand inline. @@ -145,7 +146,12 @@ function: This function returns @code{t} if @var{object} is any kind of function, i.e., can be passed to @code{funcall}. Note that @code{functionp} returns @code{t} for symbols that are function names, -and returns @code{nil} for special forms. +and returns @code{nil} for symbols that are macros or special forms. + +If @var{object} is not a function, this function ordinarily returns +@code{nil}. However, the representation of function objects is +complicated, and for efficiency reasons in rare cases this function +can return @code{t} even when @var{object} is not a function. @end defun It is also possible to find out how many arguments an arbitrary @@ -669,6 +675,22 @@ purposes, it is better to use @code{fset}, which does not keep such records. @xref{Function Cells}. @end defun +@defun function-alias-p object &optional noerror +Checks whether @var{object} is a function alias. If it is, it returns +a list of symbols representing the function alias chain, else +@code{nil}. For instance, if @code{a} is an alias for @code{b}, and +@code{b} is an alias for @code{c}: + +@example +(function-alias-p 'a) + @result{} (b c) +@end example + +If there's a loop in the definitions, an error will be signalled. If +@var{noerror} is non-@code{nil}, the non-looping parts of the chain is +returned instead. +@end defun + You cannot create a new primitive function with @code{defun} or @code{defalias}, but you can use them to change the function definition of any symbol, even one such as @code{car} or @code{x-popup-menu} whose @@ -969,14 +991,14 @@ side-effects only---the values it returns are ignored, not collected into a list. @code{mapc} always returns @var{sequence}. @end defun -@defun mapconcat function sequence separator +@defun mapconcat function sequence &optional separator @code{mapconcat} applies @var{function} to each element of @var{sequence}; the results, which must be sequences of characters (strings, vectors, or lists), are concatenated into a single string return value. Between each pair of result sequences, @code{mapconcat} inserts the characters from @var{separator}, which also must be a -string, or a vector or list of characters. @xref{Sequences Arrays -Vectors}. +string, or a vector or list of characters; a @code{nil} value is +treated as the empty string. @xref{Sequences Arrays Vectors}. The argument @var{function} must be a function that can take one argument and returns a sequence of characters: a string, a vector, or @@ -994,8 +1016,7 @@ string. @group (mapconcat (lambda (x) (format "%c" (1+ x))) - "HAL-8000" - "") + "HAL-8000") @result{} "IBM.9111" @end group @end example @@ -1494,6 +1515,116 @@ exposed to the rest of the Lisp world is considered an internal implementation detail. For this reason, we recommend against directly examining or altering the structure of closure objects. +@node OClosures +@section Open Closures + +Traditionally, functions are opaque objects which offer no other +functionality but to call them. Emacs Lisp functions aren't fully +opaque since you can extract some info out of them such as their +docstring, their arglist, or their interactive spec, but they are +mostly opaque. This is usually what we want, but occasionally we need +functions to expose a bit more information about themselves. + +OClosures are functions which carry additional type information, +and expose some information in the form of slots which you can access +via accessor functions. + +They are defined in two steps: first @code{oclosure-define} is used to +define new OClosure types by specifying the slots carried by those +OClosures, and then @code{oclosure-lambda} is used to create an +OClosure object of a given type. + +Say we want to define keyboard macros, i.e. interactive functions +which re-execute a sequence of key events. You could do it with +a plain function as follows: +@example +(defun kbd-macro (key-sequence) + (lambda (&optional arg) + (interactive "P") + (execute-kbd-macro key-sequence arg))) +@end example +But with such a definition there is no easy way to extract the +@var{key-sequence} from that function, for example to print it. + +We can solve this problem using OClosures as follows. First we define +the type of our keyboard macros (to which we decided to add +a @code{counter} slot while at it): +@example +(oclosure-define kbd-macro + "Keyboard macro." + keys (counter :mutable t)) +@end example +After which we can rewrite our @code{kbd-macro} function: +@example +(defun kbd-macro (key-sequence) + (oclosure-lambda (kbd-macro (keys key-sequence) (counter 0)) + (&optional arg) + (interactive "p") + (execute-kbd-macro keys arg) + (setq counter (1+ counter)))) +@end example +As you can see, the @code{keys} and @code{counter} slots of the +OClosure can be accessed as local variables from within the body +of the OClosure. But we can now also access them from outside of the +body of the OClosure, for example to describe a keyboard macro: +@example +(defun describe-kbd-macro (km) + (if (not (eq 'kbd-macro (oclosure-type km))) + (message "Not a keyboard macro") + (let ((keys (kbd-macro--keys km)) + (counter (kbd-macro--counter km))) + (message "Keys=%S, called %d times" keys counter)))) +@end example +Where @code{kbd-macro--keys} and @code{kbd-macro--counter} are +accessor functions generated by the @code{oclosure-define} macro. + +@defmac oclosure-define name &optional docstring &rest slots +This macro defines a new OClosure type along with accessor functions +for its slots. @var{name} can be a symbol (the name of +the new type), or a list of the form @code{(@var{name} . @var{type-props})} in +which case @var{type-props} is a list of additional properties. +@var{slots} is a list of slot descriptions where each slot can be +either a symbol (the name of the slot) or it can be of the form +@code{(@var{slot-name} . @var{slot-props})} where @var{slot-props} is +a property list. + +For each slot, the macro creates an accessor function named +@code{@var{name}--@var{slot-name}}. By default slots are immutable. +If you need a slot to be mutable, you need to specify it with the +@code{:mutable} slot property, after which it can be mutated for +example with @code{setf}. + +Beside slot accessors, the macro can create a predicate and +functional update functions according to @var{type-props}: +a @code{(:predicate @var{pred-name})} in the @var{type-props} causes +the definition of a predicate function under the name @var{pred-name}, +and @code{(:copier @var{copier-name} @var{copier-arglist})} causes the +definition of a functional update function which takes an OClosure of +type @var{name} as first argument and returns a copy of it with the +slots named in @var{copier-arglist} modified to the value passed in the +corresponding argument. +@end defmac + +@defmac oclosure-lambda (type . slots) arglist &rest body +This macro creates an anonymous OClosure of type @var{type}. +@var{slots} should be a list of elements of the form @code{(@var{slot-name} +@var{exp})}. +At run time, each @var{exp} is evaluated, in order, after which +the OClosure is created with its slots initialized with the +resulting values. + +When called as a function, the OClosure will accept arguments +according to @var{arglist} and will execute the code in @var{body}. +@var{body} can refer to the value of any of its slot directly as if it +were a local variable that had been captured by static scoping. +@end defmac + +@defun oclosure-type object +This function returns the OClosure type (a symbol) of @var{object} if it is an +OClosure, and @code{nil} otherwise. +@end defun + + @node Advising Functions @section Advising Emacs Lisp Functions @cindex advising functions @@ -1586,6 +1717,7 @@ ways to do it. The added function is also called a piece of @emph{advice}. * Advising Named Functions:: Advising named functions. * Advice Combinators:: Ways to compose advice. * Porting Old Advice:: Adapting code using the old defadvice. +* Advice and Byte Code:: Not all functions can be advised. @end menu @node Core Advising Primitives @@ -2007,6 +2139,37 @@ changing @code{ad-return-value}, whereas new @code{:after} advice cannot, so when porting such old @code{after} advice, you'll need to turn it into new @code{:around} or @code{:filter-return} advice instead. +@c This is its own node because we link to it from *Help* buffers. +@node Advice and Byte Code +@subsection Advice and Byte Code +@cindex compiler macros, advising +@cindex @code{byte-compile} and @code{byte-optimize}, advising + + Not all functions can be reliably advised. The byte compiler may +choose to replace a call to a function with a sequence of instructions +that doesn't call the function you were interested in altering. + +This usually happens due to one of the three following mechanisms: + +@table @asis +@item @code{byte-compile} properties +If a function's symbol has a @code{byte-compile} property, that +property will be used instead of the symbol's function definition. +@xref{Compilation Functions}. + +@item @code{byte-optimize} properties +If a function's symbol has a @code{byte-optimize} property, the byte +compiler may rewrite the function arguments, or decide to use a +different function altogether. + +@item @code{compiler-macro} declare forms +A function can have a special @code{compiler-macro} @code{declare} +form in its definition (@pxref{Declare Form}) that defines an +@dfn{expander} to call when compiling the function. The expander +could then cause the produced byte-code not to call the original +function. +@end table + @node Obsolete Functions @section Declaring Functions Obsolete @cindex obsolete functions @@ -2138,8 +2301,8 @@ worry about how many times the body uses the arguments, as you do for macros. Alternatively, you can define a function by providing the code which -will inline it as a compiler macro. The following macros make this -possible. +will inline it as a compiler macro (@pxref{Declare Form}). The +following macros make this possible. @c FIXME: Can define-inline use the interactive spec? @defmac define-inline name args [doc] [declare] body@dots{} @@ -2295,6 +2458,7 @@ which case the warning message gives no extra details). @var{when} should be a string indicating when the function or macro was first made obsolete. +@cindex compiler macro @item (compiler-macro @var{expander}) This can only be used for functions, and tells the compiler to use @var{expander} as an optimization function. When encountering a call to the |