annotate man/lispref/macros.texi @ 5044:e84a30b0e4a2

remove duplicative code in change_frame_size() -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-02-15 Ben Wing <ben@xemacs.org> * frame.c (change_frame_size_1): Simplify the logic in this function. (1) Don't allow 0 as the value of height or width. The old code that tried to allow this was totally broken, anyway, so obviously this never happens any more. (2) Don't duplicate the code in frame_conversion_internal() that converts displayable pixel size to total pixel size -- just call that function.
author Ben Wing <ben@xemacs.org>
date Mon, 15 Feb 2010 22:58:10 -0600
parents 755ae5b97edb
children 62b9ef1ed4ac
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
4905
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
181 function. It doesn't make sense to pass an anonymous macro to
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
182 functionals such as @code{mapcar}, and it is usually more readable to
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
183 use @code{macrolet} to make a local macro definition, and call that.
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
184 But if, for whatever reason, @code{macrolet} is not available, code
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
185 like the following may be useful:
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
186
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
187 @example
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
188 ((macro . (lambda (&rest arguments)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
189 (let (res)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
190 (while (consp arguments)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
191 (setq res (cons (cons 'put
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
192 (cons (list 'quote (car arguments))
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
193 '((quote my-property) t)))
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
194 res)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
195 arguments (cdr arguments)))
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
196 (cons 'progn res))))
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
197 + - = floor ceiling round)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
198 @end example
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
199
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
200 This expands to:
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
201
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
202 @example
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
203 (progn
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
204 (put 'round 'my-property t)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
205 (put 'ceiling 'my-property t)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
206 (put 'floor 'my-property t)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
207 (put '= 'my-property t)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
208 (put '- 'my-property t)
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
209 (put '+ 'my-property t))
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
210 @end example
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
211
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
212 In practice, almost all Lisp macros have names, and they are usually
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
213 defined with the special operator @code{defmacro}.
428
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 @defspec defmacro name argument-list body-forms@dots{}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
216 @code{defmacro} defines the symbol @var{name} as a macro that looks
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
217 like this:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
218
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
219 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
220 (macro lambda @var{argument-list} . @var{body-forms})
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
221 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
222
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
223 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
224 value returned by evaluating the @code{defmacro} form is @var{name}, but
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
225 usually we ignore this value.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
226
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
227 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
228 function, and the keywords @code{&rest} and @code{&optional} may be used
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
229 (@pxref{Argument List}). Macros may have a documentation string, but
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
230 any @code{interactive} declaration is ignored since macros cannot be
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
231 called interactively.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
232 @end defspec
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
233
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
234 @node Backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
235 @section Backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
236 @cindex backquote (list substitution)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
237 @cindex ` (list substitution)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
238 @findex `
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
239
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
240 Macros often need to construct large list structures from a mixture of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
241 constants and nonconstant parts. To make this easier, use the macro
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
242 @samp{`} (often called @dfn{backquote}).
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
243
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
244 Backquote allows you to quote a list, but selectively evaluate
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
245 elements of that list. In the simplest case, it is identical to the
4905
755ae5b97edb Change "special form" to "special operator" in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents: 2492
diff changeset
246 special operator @code{quote} (@pxref{Quoting}). For example, these
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
247 two forms yield identical results:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
248
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
249 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
250 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
251 `(a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
252 @result{} (a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
253 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
254 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
255 '(a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
256 @result{} (a list of (+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
257 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
258 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
259
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
260 @findex , @r{(with Backquote)}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
261 The special marker @samp{,} inside of the argument to backquote
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
262 indicates a value that isn't constant. Backquote evaluates the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
263 argument of @samp{,} and puts the value in the list structure:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
264
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
265 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
266 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
267 (list 'a 'list 'of (+ 2 3) 'elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
268 @result{} (a list of 5 elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
269 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
270 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
271 `(a list of ,(+ 2 3) elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
272 @result{} (a list of 5 elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
273 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
274 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
275
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
276 @findex ,@@ @r{(with Backquote)}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
277 @cindex splicing (with backquote)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
278 You can also @dfn{splice} an evaluated value into the resulting list,
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
279 using the special marker @samp{,@@}. The elements of the spliced list
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
280 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
281 list. The equivalent code without using @samp{`} is often unreadable.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
282 Here are some examples:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
283
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
284 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
285 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
286 (setq some-list '(2 3))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
287 @result{} (2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
288 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
289 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
290 (cons 1 (append some-list '(4) some-list))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
291 @result{} (1 2 3 4 2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
292 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
293 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
294 `(1 ,@@some-list 4 ,@@some-list)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
295 @result{} (1 2 3 4 2 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
296 @end group
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 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
299 (setq list '(hack foo bar))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
300 @result{} (hack foo bar)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
301 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
302 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
303 (cons 'use
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
304 (cons 'the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
305 (cons 'words (append (cdr list) '(as elements)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
306 @result{} (use the words foo bar as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
307 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
308 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
309 `(use the words ,@@(cdr list) as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
310 @result{} (use the words foo bar as elements)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
311 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
312 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
313
444
576fb035e263 Import from CVS: tag r21-2-37
cvs
parents: 428
diff changeset
314 @quotation
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
315 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
316 19.29), @samp{`} used a different syntax which required an extra level
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
317 of parentheses around the entire backquote construct. Likewise, each
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
318 @samp{,} or @samp{,@@} substitution required an extra level of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
319 parentheses surrounding both the @samp{,} or @samp{,@@} and the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
320 following expression. The old syntax required whitespace between the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
321 @samp{`}, @samp{,} or @samp{,@@} and the following expression.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
322
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
323 This syntax is still accepted, but no longer recommended except for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
324 compatibility with old Emacs versions.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
325 @end quotation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
326
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
327 @node Problems with Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
328 @section Common Problems Using Macros
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
329
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
330 The basic facts of macro expansion have counterintuitive consequences.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
331 This section describes some important consequences that can lead to
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
332 trouble, and rules to follow to avoid trouble.
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 @menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
335 * Argument Evaluation:: The expansion should evaluate each macro arg once.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
336 * Surprising Local Vars:: Local variable bindings in the expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
337 require special care.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
338 * Eval During Expansion:: Don't evaluate them; put them in the expansion.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
339 * Repeated Expansion:: Avoid depending on how many times expansion is done.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
340 @end menu
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
341
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
342 @node Argument Evaluation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
343 @subsection Evaluating Macro Arguments Repeatedly
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
344
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
345 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
346 the arguments will be evaluated when the expansion is executed. The
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
347 following macro (used to facilitate iteration) illustrates the problem.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
348 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
349 find in Pascal.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
350
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
351 @findex for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
352 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
353 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
354 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
355 "Execute a simple \"for\" loop.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
356 For example, (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
357 (list 'let (list (list var init))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
358 (cons 'while (cons (list '<= var final)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
359 (append body (list (list 'inc var)))))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
360 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
361 @result{} for
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
362
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
363 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
364 (for i from 1 to 3 do
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
365 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
366 (princ (format "\n%d %d" i square)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
367 @expansion{}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
368 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
369 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
370 (let ((i 1))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
371 (while (<= i 3)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
372 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
373 (princ (format "%d %d" i square))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
374 (inc i)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
375 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
376 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
377
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
378 @print{}1 1
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
379 @print{}2 4
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
380 @print{}3 9
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
381 @result{} nil
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
382 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
383 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
384
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
385 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
386 (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
387 ``syntactic sugar''; they are entirely ignored. The idea is that you
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
388 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
389 in those positions in the macro call.)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
390
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
391 Here's an equivalent definition simplified through use of backquote:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
392
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
393 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
394 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
395 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
396 "Execute a simple \"for\" loop.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
397 For example, (for i from 1 to 10 do (print i))."
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
398 `(let ((,var ,init))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
399 (while (<= ,var ,final)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
400 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
401 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
402 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
403 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
404
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
405 Both forms of this definition (with backquote and without) suffer from
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
406 the defect that @var{final} is evaluated on every iteration. If
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
407 @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
408 complex form, say @code{(long-complex-calculation x)}, this can slow
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
409 down the execution significantly. If @var{final} has side effects,
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
410 executing it more than once is probably incorrect.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
411
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
412 @cindex macro argument evaluation
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
413 A well-designed macro definition takes steps to avoid this problem by
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
414 producing an expansion that evaluates the argument expressions exactly
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
415 once unless repeated evaluation is part of the intended purpose of the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
416 macro. Here is a correct expansion for the @code{for} macro:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
417
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
418 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
419 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
420 (let ((i 1)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
421 (max 3))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
422 (while (<= i max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
423 (setq square (* i i))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
424 (princ (format "%d %d" i square))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
425 (inc i)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
426 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
427 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
428
444
576fb035e263 Import from CVS: tag r21-2-37
cvs
parents: 428
diff changeset
429 Here is a macro definition that creates this expansion:
428
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
430
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
431 @smallexample
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 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
434 "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
435 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
436 (max ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
437 (while (<= ,var max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
438 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
439 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
440 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
441 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
442
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
443 Unfortunately, this introduces another problem.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
444 @ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
445 Proceed to the following node.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
446 @end ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
447
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
448 @node Surprising Local Vars
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
449 @subsection Local Variables in Macro Expansions
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
450
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
451 @ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
452 In the previous section, the definition of @code{for} was fixed as
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
453 follows to make the expansion evaluate the macro arguments the proper
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
454 number of times:
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 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
457 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
458 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
459 "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
460 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
461 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
462 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
463 (max ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
464 (while (<= ,var max)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
465 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
466 (inc ,var))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
467 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
468 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
469 @end ifinfo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
470
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
471 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
472 local variable named @code{max} which the user does not expect. This
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
473 causes trouble in examples such as the following:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
474
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
475 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
476 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
477 (let ((max 0))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
478 (for x from 0 to 10 do
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
479 (let ((this (frob x)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
480 (if (< max this)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
481 (setq max this)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
482 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
483 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
484
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
485 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
486 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
487 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
488 the binding made by @code{for}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
489
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
490 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
491 @code{max} (@pxref{Creating Symbols}). The uninterned symbol can be
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
492 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
493 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
494 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
495 put it into the program later. It will never appear anywhere except
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
496 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
497 this way:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
498
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
499 @smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
500 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
501 (defmacro for (var from init to final do &rest body)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
502 "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
503 (let ((tempvar (make-symbol "max")))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
504 `(let ((,var ,init)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
505 (,tempvar ,final))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
506 (while (<= ,var ,tempvar)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
507 ,@@body
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
508 (inc ,var)))))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
509 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
510 @end smallexample
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
511
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
512 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
513 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
514 expansion instead of the usual interned symbol @code{max} that appears
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
515 in expressions ordinarily.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
516
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
517 @node Eval During Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
518 @subsection Evaluating Macro Arguments in Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
519
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
520 Another problem can happen if you evaluate any of the macro argument
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
521 expressions during the computation of the expansion, such as by calling
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
522 @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
523 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
524 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
525 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
526 variable, so any references inside the form being evaluated do refer
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
527 to it. Here is an example:
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 @example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
530 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
531 (defmacro foo (a)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
532 (list 'setq (eval a) t))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
533 @result{} foo
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
534 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
535 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
536 (setq x 'b)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
537 (foo x) @expansion{} (setq b t)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
538 @result{} t ; @r{and @code{b} has been set.}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
539 ;; @r{but}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
540 (setq a 'c)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
541 (foo a) @expansion{} (setq a t)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
542 @result{} t ; @r{but this set @code{a}, not @code{c}.}
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
543
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
544 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
545 @end example
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
546
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
547 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
548 @code{x}, because @code{a} conflicts with the macro argument variable
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
549 @code{a}.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
550
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
551 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
552 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
553 byte-compiler runs macro definitions while compiling the program, when
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
554 the program's own computations (which you might have wished to access
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
555 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
556 exist.
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 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
559 put the expression into the macro expansion, so that its value is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
560 computed as part of executing the expansion.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
561
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
562 @node Repeated Expansion
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
563 @subsection How Many Times is the Macro Expanded?
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
564
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
565 Occasionally problems result from the fact that a macro call is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
566 expanded each time it is evaluated in an interpreted function, but is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
567 expanded only once (during compilation) for a compiled function. If the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
568 macro definition has side effects, they will work differently depending
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
569 on how many times the macro is expanded.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
570
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
571 In particular, constructing objects is a kind of side effect. If the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
572 macro is called once, then the objects are constructed only once. In
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
573 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
574 call is executed. In interpreted operation, the macro is reexpanded
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
575 each time, producing a fresh collection of objects each time. Usually
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
576 this does not matter---the objects have the same contents whether they
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
577 are shared or not. But if the surrounding program does side effects
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
578 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
579 an example:
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
580
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
581 @lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
582 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
583 (defmacro empty-object ()
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
584 (list 'quote (cons nil nil)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
585 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
586
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
587 @group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
588 (defun initialize (condition)
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
589 (let ((object (empty-object)))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
590 (if condition
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
591 (setcar object condition))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
592 object))
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
593 @end group
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
594 @end lisp
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
595
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
596 @noindent
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
597 If @code{initialize} is interpreted, a new list @code{(nil)} is
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
598 constructed each time @code{initialize} is called. Thus, no side effect
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
599 survives between calls. If @code{initialize} is compiled, then the
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
600 macro @code{empty-object} is expanded during compilation, producing a
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
601 single ``constant'' @code{(nil)} that is reused and altered each time
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
602 @code{initialize} is called.
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
603
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
604 One way to avoid pathological cases like this is to think of
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
605 @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
606 allocation construct. You wouldn't use @code{setcar} on a constant such
3ecd8885ac67 Import from CVS: tag r21-2-22
cvs
parents:
diff changeset
607 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
608 either.