annotate man/lispref/macros.texi @ 4792:95b04754ea8c

Make #'equalp more compatible with CL; add a compiler macro, test & doc it. lisp/ChangeLog addition: 2009-11-08 Aidan Kehoe <kehoea@parhasard.net> * cl-extra.el (cl-string-vector-equalp) (cl-bit-vector-vector-equalp, cl-vector-array-equalp) (cl-hash-table-contents-equalp): New functions, to implement equalp treating arrays with identical contents as equivalent, as specified by Common Lisp. (equalp): Revise this function to implement array equivalence, and the hash-table equalp behaviour specified by CL. * cl-macs.el (equalp): Add a compiler macro for this function, used when one of the arguments is constant, and as such, its type is known at compile time. man/ChangeLog addition: 2009-11-08 Aidan Kehoe <kehoea@parhasard.net> * lispref/objects.texi (Equality Predicates): Document #'equalp here, as well as #'equal and #'eq. tests/ChangeLog addition: 2009-12-31 Aidan Kehoe <kehoea@parhasard.net> * automated/lisp-tests.el: Test much of the functionality of equalp; add a pointer to Paul Dietz' ANSI test suite for this function, converted to Emacs Lisp. Not including the tests themselves in XEmacs because who owns the copyright on the files is unclear and the GCL people didn't respond to my queries.
author Aidan Kehoe <kehoea@parhasard.net>
date Thu, 31 Dec 2009 15:09:41 +0000
parents 6780963faf78
children 755ae5b97edb
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
1 @c -*-texinfo-*-
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
2 @c This is part of the XEmacs Lisp Reference Manual.
444
576fb035e263 Import from CVS: tag r21-2-37
cvs
parents: 428
diff changeset
3 @c Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
4 @c See the file lispref.texi for copying conditions.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
5 @setfilename ../../info/macros.info
2492
6780963faf78 [xemacs-hg @ 2005-01-21 09:43:09 by aidan]
aidan
parents: 444
diff changeset
6 @node Macros, Loading, Functions and Commands, Top
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
7 @chapter Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
8 @cindex macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
9
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
10 @dfn{Macros} enable you to define new control constructs and other
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
11 language features. A macro is defined much like a function, but instead
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
12 of telling how to compute a value, it tells how to compute another Lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
13 expression which will in turn compute the value. We call this
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
14 expression the @dfn{expansion} of the macro.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
15
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
16 Macros can do this because they operate on the unevaluated expressions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
17 for the arguments, not on the argument values as functions do. They can
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
18 therefore construct an expansion containing these argument expressions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
19 or parts of them.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
20
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
21 If you are using a macro to do something an ordinary function could
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
22 do, just for the sake of speed, consider using an inline function
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
23 instead. @xref{Inline Functions}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
24
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
25 @menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
26 * Simple Macro:: A basic example.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
27 * Expansion:: How, when and why macros are expanded.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
28 * Compiling Macros:: How macros are expanded by the compiler.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
29 * Defining Macros:: How to write a macro definition.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
30 * Backquote:: Easier construction of list structure.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
31 * Problems with Macros:: Don't evaluate the macro arguments too many times.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
32 Don't hide the user's variables.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
33 @end menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
34
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
35 @node Simple Macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
36 @section A Simple Example of a Macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
37
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
38 Suppose we would like to define a Lisp construct to increment a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
39 variable value, much like the @code{++} operator in C. We would like to
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
40 write @code{(inc x)} and have the effect of @code{(setq x (1+ x))}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
41 Here's a macro definition that does the job:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
42
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
43 @findex inc
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
44 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
45 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
46 (defmacro inc (var)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
47 (list 'setq var (list '1+ var)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
48 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
49 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
50
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
51 When this is called with @code{(inc x)}, the argument @code{var} has
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
52 the value @code{x}---@emph{not} the @emph{value} of @code{x}. The body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
53 of the macro uses this to construct the expansion, which is @code{(setq
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
54 x (1+ x))}. Once the macro definition returns this expansion, Lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
55 proceeds to evaluate it, thus incrementing @code{x}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
56
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
57 @node Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
58 @section Expansion of a Macro Call
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
59 @cindex expansion of macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
60 @cindex macro call
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
61
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
62 A macro call looks just like a function call in that it is a list which
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
63 starts with the name of the macro. The rest of the elements of the list
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
64 are the arguments of the macro.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
65
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
66 Evaluation of the macro call begins like evaluation of a function call
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
67 except for one crucial difference: the macro arguments are the actual
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
68 expressions appearing in the macro call. They are not evaluated before
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
69 they are given to the macro definition. By contrast, the arguments of a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
70 function are results of evaluating the elements of the function call
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
71 list.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
72
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
73 Having obtained the arguments, Lisp invokes the macro definition just
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
74 as a function is invoked. The argument variables of the macro are bound
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
75 to the argument values from the macro call, or to a list of them in the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
76 case of a @code{&rest} argument. And the macro body executes and
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
77 returns its value just as a function body does.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
78
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
79 The second crucial difference between macros and functions is that the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
80 value returned by the macro body is not the value of the macro call.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
81 Instead, it is an alternate expression for computing that value, also
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
82 known as the @dfn{expansion} of the macro. The Lisp interpreter
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
83 proceeds to evaluate the expansion as soon as it comes back from the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
84 macro.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
85
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
86 Since the expansion is evaluated in the normal manner, it may contain
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
87 calls to other macros. It may even be a call to the same macro, though
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
88 this is unusual.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
89
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
90 You can see the expansion of a given macro call by calling
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
91 @code{macroexpand}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
92
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
93 @defun macroexpand form &optional environment
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
94 @cindex macro expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
95 This function expands @var{form}, if it is a macro call. If the result
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
96 is another macro call, it is expanded in turn, until something which is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
97 not a macro call results. That is the value returned by
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
98 @code{macroexpand}. If @var{form} is not a macro call to begin with, it
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
99 is returned as given.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
100
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
101 Note that @code{macroexpand} does not look at the subexpressions of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
102 @var{form} (although some macro definitions may do so). Even if they
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
103 are macro calls themselves, @code{macroexpand} does not expand them.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
104
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
105 The function @code{macroexpand} does not expand calls to inline functions.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
106 Normally there is no need for that, since a call to an inline function is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
107 no harder to understand than a call to an ordinary function.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
108
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
109 If @var{environment} is provided, it specifies an alist of macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
110 definitions that shadow the currently defined macros. Byte compilation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
111 uses this feature.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
112
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
113 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
114 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
115 (defmacro inc (var)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
116 (list 'setq var (list '1+ var)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
117 @result{} inc
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
118 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
119
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
120 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
121 (macroexpand '(inc r))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
122 @result{} (setq r (1+ r))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
123 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
124
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
125 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
126 (defmacro inc2 (var1 var2)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
127 (list 'progn (list 'inc var1) (list 'inc var2)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
128 @result{} inc2
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
129 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
130
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
131 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
132 (macroexpand '(inc2 r s))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
133 @result{} (progn (inc r) (inc s)) ; @r{@code{inc} not expanded here.}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
134 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
135 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
136 @end defun
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
137
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
138 @node Compiling Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
139 @section Macros and Byte Compilation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
140 @cindex byte-compiling macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
141
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
142 You might ask why we take the trouble to compute an expansion for a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
143 macro and then evaluate the expansion. Why not have the macro body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
144 produce the desired results directly? The reason has to do with
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
145 compilation.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
146
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
147 When a macro call appears in a Lisp program being compiled, the Lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
148 compiler calls the macro definition just as the interpreter would, and
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
149 receives an expansion. But instead of evaluating this expansion, it
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
150 compiles the expansion as if it had appeared directly in the program.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
151 As a result, the compiled code produces the value and side effects
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
152 intended for the macro, but executes at full compiled speed. This would
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
153 not work if the macro body computed the value and side effects
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
154 itself---they would be computed at compile time, which is not useful.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
155
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
156 In order for compilation of macro calls to work, the macros must be
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
157 defined in Lisp when the calls to them are compiled. The compiler has a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
158 special feature to help you do this: if a file being compiled contains a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
159 @code{defmacro} form, the macro is defined temporarily for the rest of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
160 the compilation of that file. To use this feature, you must define the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
161 macro in the same file where it is used and before its first use.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
162
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
163 Byte-compiling a file executes any @code{require} calls at top-level
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
164 in the file. This is in case the file needs the required packages for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
165 proper compilation. One way to ensure that necessary macro definitions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
166 are available during compilation is to require the files that define
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
167 them (@pxref{Named Features}). To avoid loading the macro definition files
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
168 when someone @emph{runs} the compiled program, write
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
169 @code{eval-when-compile} around the @code{require} calls (@pxref{Eval
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
170 During Compile}).
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
171
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
172 @node Defining Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
173 @section Defining Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
174
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
175 A Lisp macro is a list whose @sc{car} is @code{macro}. Its @sc{cdr} should
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
176 be a function; expansion of the macro works by applying the function
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
177 (with @code{apply}) to the list of unevaluated argument-expressions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
178 from the macro call.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
179
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
180 It is possible to use an anonymous Lisp macro just like an anonymous
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
181 function, but this is never done, because it does not make sense to pass
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
182 an anonymous macro to functionals such as @code{mapcar}. In practice,
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
183 all Lisp macros have names, and they are usually defined with the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
184 special form @code{defmacro}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
185
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
186 @defspec defmacro name argument-list body-forms@dots{}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
187 @code{defmacro} defines the symbol @var{name} as a macro that looks
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
188 like this:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
189
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
190 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
191 (macro lambda @var{argument-list} . @var{body-forms})
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
192 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
193
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
194 This macro object is stored in the function cell of @var{name}. The
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
195 value returned by evaluating the @code{defmacro} form is @var{name}, but
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
196 usually we ignore this value.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
197
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
198 The shape and meaning of @var{argument-list} is the same as in a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
199 function, and the keywords @code{&rest} and @code{&optional} may be used
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
200 (@pxref{Argument List}). Macros may have a documentation string, but
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
201 any @code{interactive} declaration is ignored since macros cannot be
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
202 called interactively.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
203 @end defspec
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
204
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
205 @node Backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
206 @section Backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
207 @cindex backquote (list substitution)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
208 @cindex ` (list substitution)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
209 @findex `
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
210
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
211 Macros often need to construct large list structures from a mixture of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
212 constants and nonconstant parts. To make this easier, use the macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
213 @samp{`} (often called @dfn{backquote}).
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
214
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
215 Backquote allows you to quote a list, but selectively evaluate
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
216 elements of that list. In the simplest case, it is identical to the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
217 special form @code{quote} (@pxref{Quoting}). For example, these
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
218 two forms yield identical results:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
219
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
220 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
221 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
222 `(a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
223 @result{} (a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
224 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
225 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
226 '(a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
227 @result{} (a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
228 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
229 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
230
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
231 @findex , @r{(with Backquote)}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
232 The special marker @samp{,} inside of the argument to backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
233 indicates a value that isn't constant. Backquote evaluates the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
234 argument of @samp{,} and puts the value in the list structure:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
235
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
236 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
237 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
238 (list 'a 'list 'of (+ 2 3) 'elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
239 @result{} (a list of 5 elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
240 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
241 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
242 `(a list of ,(+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
243 @result{} (a list of 5 elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
244 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
245 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
246
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
247 @findex ,@@ @r{(with Backquote)}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
248 @cindex splicing (with backquote)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
249 You can also @dfn{splice} an evaluated value into the resulting list,
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
250 using the special marker @samp{,@@}. The elements of the spliced list
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
251 become elements at the same level as the other elements of the resulting
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
252 list. The equivalent code without using @samp{`} is often unreadable.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
253 Here are some examples:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
254
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
255 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
256 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
257 (setq some-list '(2 3))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
258 @result{} (2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
259 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
260 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
261 (cons 1 (append some-list '(4) some-list))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
262 @result{} (1 2 3 4 2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
263 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
264 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
265 `(1 ,@@some-list 4 ,@@some-list)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
266 @result{} (1 2 3 4 2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
267 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
268
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
269 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
270 (setq list '(hack foo bar))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
271 @result{} (hack foo bar)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
272 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
273 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
274 (cons 'use
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
275 (cons 'the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
276 (cons 'words (append (cdr list) '(as elements)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
277 @result{} (use the words foo bar as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
278 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
279 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
280 `(use the words ,@@(cdr list) as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
281 @result{} (use the words foo bar as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
282 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
283 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
284
444
576fb035e263 Import from CVS: tag r21-2-37
cvs
parents: 428
diff changeset
285 @quotation
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
286 In older versions of Emacs (before XEmacs 19.12 or FSF Emacs version
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
287 19.29), @samp{`} used a different syntax which required an extra level
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
288 of parentheses around the entire backquote construct. Likewise, each
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
289 @samp{,} or @samp{,@@} substitution required an extra level of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
290 parentheses surrounding both the @samp{,} or @samp{,@@} and the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
291 following expression. The old syntax required whitespace between the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
292 @samp{`}, @samp{,} or @samp{,@@} and the following expression.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
293
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
294 This syntax is still accepted, but no longer recommended except for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
295 compatibility with old Emacs versions.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
296 @end quotation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
297
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
298 @node Problems with Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
299 @section Common Problems Using Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
300
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
301 The basic facts of macro expansion have counterintuitive consequences.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
302 This section describes some important consequences that can lead to
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
303 trouble, and rules to follow to avoid trouble.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
304
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
305 @menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
306 * Argument Evaluation:: The expansion should evaluate each macro arg once.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
307 * Surprising Local Vars:: Local variable bindings in the expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
308 require special care.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
309 * Eval During Expansion:: Don't evaluate them; put them in the expansion.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
310 * Repeated Expansion:: Avoid depending on how many times expansion is done.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
311 @end menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
312
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
313 @node Argument Evaluation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
314 @subsection Evaluating Macro Arguments Repeatedly
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
315
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
316 When defining a macro you must pay attention to the number of times
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
317 the arguments will be evaluated when the expansion is executed. The
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
318 following macro (used to facilitate iteration) illustrates the problem.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
319 This macro allows us to write a simple ``for'' loop such as one might
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
320 find in Pascal.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
321
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
322 @findex for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
323 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
324 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
325 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
326 "Execute a simple \"for\" loop.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
327 For example, (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
328 (list 'let (list (list var init))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
329 (cons 'while (cons (list '<= var final)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
330 (append body (list (list 'inc var)))))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
331 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
332 @result{} for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
333
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
334 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
335 (for i from 1 to 3 do
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
336 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
337 (princ (format "\n%d %d" i square)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
338 @expansion{}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
339 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
340 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
341 (let ((i 1))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
342 (while (<= i 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
343 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
344 (princ (format "%d %d" i square))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
345 (inc i)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
346 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
347 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
348
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
349 @print{}1 1
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
350 @print{}2 4
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
351 @print{}3 9
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
352 @result{} nil
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
353 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
354 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
355
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
356 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
357 (The arguments @code{from}, @code{to}, and @code{do} in this macro are
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
358 ``syntactic sugar''; they are entirely ignored. The idea is that you
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
359 will write noise words (such as @code{from}, @code{to}, and @code{do})
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
360 in those positions in the macro call.)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
361
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
362 Here's an equivalent definition simplified through use of backquote:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
363
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
364 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
365 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
366 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
367 "Execute a simple \"for\" loop.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
368 For example, (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
369 `(let ((,var ,init))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
370 (while (<= ,var ,final)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
371 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
372 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
373 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
374 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
375
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
376 Both forms of this definition (with backquote and without) suffer from
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
377 the defect that @var{final} is evaluated on every iteration. If
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
378 @var{final} is a constant, this is not a problem. If it is a more
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
379 complex form, say @code{(long-complex-calculation x)}, this can slow
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
380 down the execution significantly. If @var{final} has side effects,
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
381 executing it more than once is probably incorrect.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
382
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
383 @cindex macro argument evaluation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
384 A well-designed macro definition takes steps to avoid this problem by
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
385 producing an expansion that evaluates the argument expressions exactly
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
386 once unless repeated evaluation is part of the intended purpose of the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
387 macro. Here is a correct expansion for the @code{for} macro:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
388
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
389 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
390 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
391 (let ((i 1)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
392 (max 3))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
393 (while (<= i max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
394 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
395 (princ (format "%d %d" i square))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
396 (inc i)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
397 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
398 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
399
444
576fb035e263 Import from CVS: tag r21-2-37
cvs
parents: 428
diff changeset
400 Here is a macro definition that creates this expansion:
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
401
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
402 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
403 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
404 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
405 "Execute a simple for loop: (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
406 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
407 (max ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
408 (while (<= ,var max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
409 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
410 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
411 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
412 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
413
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
414 Unfortunately, this introduces another problem.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
415 @ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
416 Proceed to the following node.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
417 @end ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
418
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
419 @node Surprising Local Vars
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
420 @subsection Local Variables in Macro Expansions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
421
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
422 @ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
423 In the previous section, the definition of @code{for} was fixed as
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
424 follows to make the expansion evaluate the macro arguments the proper
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
425 number of times:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
426
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
427 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
428 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
429 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
430 "Execute a simple for loop: (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
431 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
432 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
433 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
434 (max ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
435 (while (<= ,var max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
436 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
437 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
438 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
439 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
440 @end ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
441
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
442 The new definition of @code{for} has a new problem: it introduces a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
443 local variable named @code{max} which the user does not expect. This
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
444 causes trouble in examples such as the following:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
445
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
446 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
447 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
448 (let ((max 0))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
449 (for x from 0 to 10 do
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
450 (let ((this (frob x)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
451 (if (< max this)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
452 (setq max this)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
453 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
454 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
455
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
456 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
457 The references to @code{max} inside the body of the @code{for}, which
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
458 are supposed to refer to the user's binding of @code{max}, really access
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
459 the binding made by @code{for}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
460
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
461 The way to correct this is to use an uninterned symbol instead of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
462 @code{max} (@pxref{Creating Symbols}). The uninterned symbol can be
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
463 bound and referred to just like any other symbol, but since it is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
464 created by @code{for}, we know that it cannot already appear in the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
465 user's program. Since it is not interned, there is no way the user can
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
466 put it into the program later. It will never appear anywhere except
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
467 where put by @code{for}. Here is a definition of @code{for} that works
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
468 this way:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
469
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
470 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
471 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
472 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
473 "Execute a simple for loop: (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
474 (let ((tempvar (make-symbol "max")))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
475 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
476 (,tempvar ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
477 (while (<= ,var ,tempvar)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
478 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
479 (inc ,var)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
480 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
481 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
482
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
483 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
484 This creates an uninterned symbol named @code{max} and puts it in the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
485 expansion instead of the usual interned symbol @code{max} that appears
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
486 in expressions ordinarily.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
487
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
488 @node Eval During Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
489 @subsection Evaluating Macro Arguments in Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
490
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
491 Another problem can happen if you evaluate any of the macro argument
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
492 expressions during the computation of the expansion, such as by calling
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
493 @code{eval} (@pxref{Eval}). If the argument is supposed to refer to the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
494 user's variables, you may have trouble if the user happens to use a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
495 variable with the same name as one of the macro arguments. Inside the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
496 macro body, the macro argument binding is the most local binding of this
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
497 variable, so any references inside the form being evaluated do refer
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
498 to it. Here is an example:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
499
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
500 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
501 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
502 (defmacro foo (a)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
503 (list 'setq (eval a) t))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
504 @result{} foo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
505 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
506 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
507 (setq x 'b)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
508 (foo x) @expansion{} (setq b t)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
509 @result{} t ; @r{and @code{b} has been set.}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
510 ;; @r{but}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
511 (setq a 'c)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
512 (foo a) @expansion{} (setq a t)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
513 @result{} t ; @r{but this set @code{a}, not @code{c}.}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
514
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
515 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
516 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
517
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
518 It makes a difference whether the user's variable is named @code{a} or
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
519 @code{x}, because @code{a} conflicts with the macro argument variable
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
520 @code{a}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
521
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
522 Another reason not to call @code{eval} in a macro definition is that
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
523 it probably won't do what you intend in a compiled program. The
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
524 byte-compiler runs macro definitions while compiling the program, when
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
525 the program's own computations (which you might have wished to access
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
526 with @code{eval}) don't occur and its local variable bindings don't
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
527 exist.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
528
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
529 The safe way to work with the run-time value of an expression is to
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
530 put the expression into the macro expansion, so that its value is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
531 computed as part of executing the expansion.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
532
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
533 @node Repeated Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
534 @subsection How Many Times is the Macro Expanded?
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
535
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
536 Occasionally problems result from the fact that a macro call is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
537 expanded each time it is evaluated in an interpreted function, but is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
538 expanded only once (during compilation) for a compiled function. If the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
539 macro definition has side effects, they will work differently depending
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
540 on how many times the macro is expanded.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
541
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
542 In particular, constructing objects is a kind of side effect. If the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
543 macro is called once, then the objects are constructed only once. In
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
544 other words, the same structure of objects is used each time the macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
545 call is executed. In interpreted operation, the macro is reexpanded
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
546 each time, producing a fresh collection of objects each time. Usually
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
547 this does not matter---the objects have the same contents whether they
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
548 are shared or not. But if the surrounding program does side effects
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
549 on the objects, it makes a difference whether they are shared. Here is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
550 an example:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
551
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
552 @lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
553 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
554 (defmacro empty-object ()
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
555 (list 'quote (cons nil nil)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
556 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
557
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
558 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
559 (defun initialize (condition)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
560 (let ((object (empty-object)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
561 (if condition
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
562 (setcar object condition))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
563 object))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
564 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
565 @end lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
566
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
567 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
568 If @code{initialize} is interpreted, a new list @code{(nil)} is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
569 constructed each time @code{initialize} is called. Thus, no side effect
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
570 survives between calls. If @code{initialize} is compiled, then the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
571 macro @code{empty-object} is expanded during compilation, producing a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
572 single ``constant'' @code{(nil)} that is reused and altered each time
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
573 @code{initialize} is called.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
574
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
575 One way to avoid pathological cases like this is to think of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
576 @code{empty-object} as a funny kind of constant, not as a memory
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
577 allocation construct. You wouldn't use @code{setcar} on a constant such
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
578 as @code{'(nil)}, so naturally you won't use it on @code{(empty-object)}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
579 either.