1
0
Fork 0
cl-sites/HyperSpec-7-0/HyperSpec/Issues/iss095_w.htm
2024-04-01 10:24:07 +02:00

242 lines
18 KiB
HTML

<!-- Common Lisp HyperSpec (TM), version 7.0 generated by Kent M. Pitman on Mon, 11-Apr-2005 2:31am EDT -->
<HTML>
<HEAD>
<TITLE>CLHS: Issue DECLARE-MACROS Writeup</TITLE>
<LINK HREF="../Data/clhs.css" REL="stylesheet" TYPE="text/css" />
<META HTTP-EQUIV="Author" CONTENT="Kent M. Pitman">
<META HTTP-EQUIV="Organization" CONTENT="LispWorks Ltd.">
<LINK REL=TOP HREF="../Front/index.htm">
<LINK REL=COPYRIGHT HREF="../Front/Help.htm#Legal">
<LINK REL=DISCLAIMER HREF="../Front/Help.htm#Disclaimer">
<LINK REL=PREV HREF="../Issues/iss094_w.htm">
<LINK REL=UP HREF="../Issues/iss095.htm">
<LINK REL=NEXT HREF="../Issues/iss096_w.htm">
</HEAD>
<BODY>
<H1><A REV=MADE HREF="http://www.lispworks.com/"><IMG WIDTH=80 HEIGHT=65 ALT="[LISPWORKS]" SRC="../Graphics/LWSmall.gif" ALIGN=Bottom></A><A REL=TOP HREF="../Front/index.htm"><IMG WIDTH=237 HEIGHT=65 ALT="[Common Lisp HyperSpec (TM)]" SRC="../Graphics/CLHS_Sm.gif" ALIGN=Bottom></A> <A REL=PREV HREF="../Issues/iss094_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss095.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss096_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
<HR>
<H2>Issue DECLARE-MACROS Writeup</H2>
<PRE><B>Issue:</B> <A HREF="iss095.htm">DECLARE-MACROS</A> <P>
<B>References:</B> Declaration Syntax (p154)<P>
<B>Category:</B> CHANGE<P>
<B>Edit history:</B> 22-Oct-87, Version 1 by Pitman<P>
9-Nov-87, Version 2 by Masinter<P>
5-Feb-88, Version 3 by Pitman<P>
<P>
<B>Problem Description:<P>
</B><P>
It is permissible for a macro call to expand into a declaration and be<P>
recognized as such. This linguistic feature provides some useful<P>
flexibility, but has a number of disadvantages:<P>
<P>
* Operations on the executable portion of a body of code inside a <P>
binding form (such as inserting an additional form) is a complicated<P>
operation. This is because one or more trial macro expansions must be<P>
done in order to pass over any declarations or documentation string<P>
and find the beginning of the body.<P>
<P>
* In order to find the end of the declarations, <A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand"><B>MACROEXPAND</B></A> must be<P>
called until a non-macro form is seen or until a macro does not expand<P>
into a macro. In some interpreters which do macro expansion on the fly,<P>
this may cause inefficiency because macro expansion of the first form<P>
in a body must be done twice. In implementations where this is <P>
optimized, the implementor may resent the fact that an optimization is<P>
needed in the first place.<P>
<P>
* Various code analysis tools have been shown to have been significantly<P>
slowed down by the need to expand macros in order to determine whether<P>
a binding is <A REL=DEFINITION HREF="../Body/d_specia.htm#special"><B>SPECIAL</B></A> when analyzing a variable binding form. This is<P>
particularly serious when macro invocations are deeply nested; the<P>
number of macro expansions can be exponential in the depth of nesting<P>
unless a macro-expansion caching mechanism is added. <P>
<P>
* User macros must be very careful about finding declarations in a body<P>
of code by doing proper macro expansion. Often, however, naive users<P>
don't realize this and so unknowingly write buggy code. This problem can<P>
be (and is) defined away as simply a programmer error, but this is a<P>
place where we could fairly straightforwardly redefine the language to<P>
better accommodate what has been shown to be a common expectation of the<P>
naive user.<P>
<P>
<B>Proposal (DECLARE-MACROS:FLUSH):<P>
</B><P>
Under this proposal, it would not be &quot;permissible for a macro call to<P>
expand into a declaration and be recognized as such, provided that the<P>
macro call appears where a declaration may legitimately appear.&quot; (CLtL<P>
p. 154). Macros could not legitimately expand into declarations; the only<P>
valid declarations would be a list whose <A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> is the symbol <A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A>.<P>
<P>
It would still be possible for a macro call to expand into a <A REL=DEFINITION HREF="../Body/f_procla.htm#proclaim"><B>PROCLAIM</B></A><P>
form, however.<P>
<P>
<B>Rationale:<P>
</B><P>
The ability to have a macro form expand into a declaration has been shown<P>
to be useful in some situations. More often, however, the presence of<P>
this feature has been seen to cause problems elsewhere in the language.<P>
Ultimately, its benefits have not outweighed its costs.<P>
<P>
<B>Current Practice:<P>
</B><P>
Most or all implementations support the old behavior even though few<P>
user programs probably need it.<P>
<P>
Some user macros are careful about finding declarations in a body of code<P>
by doing proper macro expansion, but some probably cheat and look just<P>
for explicit uses of <A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A>. The cheat probably works most of the time.<P>
<P>
<B>Cost to implementors:<P>
</B><P>
The nature of this change is such that implementations which did not<P>
choose to change would simply be supporting an implementation-dependent<P>
extension (except for some `minor' worry about destructive modification<P>
due to macro expanding while <A REL=DEFINITION HREF="../Body/v_mexp_h.htm#STmacroexpand-hookST"><B>*MACROEXPAND-HOOK*</B></A> is set to something<P>
which implemented displacing macros).<P>
<P>
In any case, there might be several places in which the interpreter,<P>
compiler, and system macros had knowledge about doing macro expansion<P>
before declaration processing. The change is not trivial, but most of<P>
its complexity is likely to be in finding the places which need change<P>
and not in making the actual change.<P>
<P>
<B>Cost to users:<P>
</B><P>
Most users probably do not write macros which expand into <A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> forms<P>
so most users are probably not affected.<P>
<P>
Users who do exploit this feature probably know that they do. In any<P>
case, compilers could be made to detect cases where this feature is<P>
being exploited and warn about it.<P>
<P>
Franz and Gold Hill are notable exceptions to the claim that users may<P>
not want this. Both claim to make a reasonable amount of use of macros<P>
which expand into different <A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> and <A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> declarations, usually<P>
dependent on a global switch.<P>
<P>
Rewrites must be devised on a case-by-case basis. A common sort of<P>
rewrite would take the form:<P>
<P>
Old code: (<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> SPEEDY ()<P>
`(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#optimize"><B>OPTIMIZE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> 3) (<A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> 0))))<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> (..bindings..) (SPEEDY) ..body..)<P>
<P>
New code: (<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> SPEEDY-LET (BVL <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> FORMS)<P>
`(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> ,BVL<P>
(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#optimize"><B>OPTIMIZE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> 3) (<A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> 0)))<P>
,@FORMS))<P>
(SPEEDY-LET (..bindings..) ..body..)<P>
<P>
Another tactic would be:<P>
<P>
Old code: (<A REL=DEFINITION HREF="../Body/s_eval_w.htm#eval-when"><B>EVAL-WHEN</B></A> (<A REL=DEFINITION HREF="../Body/f_eval.htm#eval"><B>EVAL</B></A> <A REL=DEFINITION HREF="../Body/f_cmp.htm#compile"><B>COMPILE</B></A> <A REL=DEFINITION HREF="../Body/f_load.htm#load"><B>LOAD</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_defpar.htm#defvar"><B>DEFVAR</B></A> *SPEEDY* <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> USE-STANDARD-SPEED-AND-SAFETY ()<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>IF</B></A> *SPEEDY*<P>
`(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#optimize"><B>OPTIMIZE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> 3) (<A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> 0)))<P>
`(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#optimize"><B>OPTIMIZE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> 0) (<A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> 3)))))<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> FOO ()<P>
(USE-STANDARD-SPEED-AND-SAFETY)<P>
...)<P>
New code: (<A REL=DEFINITION HREF="../Body/s_eval_w.htm#eval-when"><B>EVAL-WHEN</B></A> (<A REL=DEFINITION HREF="../Body/f_eval.htm#eval"><B>EVAL</B></A> <A REL=DEFINITION HREF="../Body/f_cmp.htm#compile"><B>COMPILE</B></A> <A REL=DEFINITION HREF="../Body/f_load.htm#load"><B>LOAD</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_defpar.htm#defvar"><B>DEFVAR</B></A> *STANDARD-SPEED-AND-SAFETY* '((<A REL=DEFINITION HREF="../Body/d_optimi.htm#speed"><B>SPEED</B></A> 0) (<A REL=DEFINITION HREF="../Body/d_optimi.htm#safety"><B>SAFETY</B></A> 3))))<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> FOO ()<P>
(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A> (<A REL=DEFINITION HREF="../Body/d_optimi.htm#optimize"><B>OPTIMIZE</B></A> #.*STANDARD-SPEED-AND-SAFETY*))<P>
...)<P>
<P>
Still a third tactic would be to actually shadow <A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A>, <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A>, etc. with<P>
variants that process macro expansions and then to build code in a<P>
package that used the revised <A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A>, <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A>, etc. eg,<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> PARSE-BODY (BODY ENV)<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> ((DECLS '())<P>
(DOC '()))<P>
(<A REL=DEFINITION HREF="../Body/m_do_do.htm#do"><B>DO</B></A> () ((<A REL=DEFINITION HREF="../Body/a_null.htm#null"><B>NULL</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#cdr"><B>CDR</B></A> BODY)))<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> ((<A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A> (<A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand"><B>MACROEXPAND</B></A> (<A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A> BODY) ENV)))<P>
(<A REL=DEFINITION HREF="../Body/m_cond.htm#cond"><B>COND</B></A> ((<A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>AND</B></A> (<A REL=DEFINITION HREF="../Body/f_stgp.htm#stringp"><B>STRINGP</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A>) BODY)<P>
(<A REL=DEFINITION HREF="../Body/m_when_.htm#unless"><B>UNLESS</B></A> (<A REL=DEFINITION HREF="../Body/a_null.htm#null"><B>NULL</B></A> DOC)<P>
(<A REL=DEFINITION HREF="../Body/f_warn.htm#warn"><B>WARN</B></A> &quot;More than one <A REL=DEFINITION HREF="../Body/f_docume.htm#documentation"><B>documentation</B></A> <A REL=DEFINITION HREF="../Body/a_string.htm#string"><B>string</B></A> was seen.&quot;))<P>
(<A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A> DOC))<P>
((<A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>AND</B></A> (<A REL=DEFINITION HREF="../Body/a_not.htm#not"><B>NOT</B></A> (<A REL=DEFINITION HREF="../Body/a_atom.htm#atom"><B>ATOM</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A>)) (<A REL=DEFINITION HREF="../Body/f_eq.htm#eq"><B>EQ</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A>) '<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>DECLARE</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A> DECLS))<P>
(T<P>
(<A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A> <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>EXP</B></A> BODY)<P>
(<A REL=DEFINITION HREF="../Body/m_return.htm#return"><B>RETURN</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>)))))<P>
(<A REL=DEFINITION HREF="../Body/a_values.htm#values"><B>VALUES</B></A> BODY (<A REL=DEFINITION HREF="../Body/f_revers.htm#nreverse"><B>NREVERSE</B></A> DECLS) (<A REL=DEFINITION HREF="../Body/f_revers.htm#nreverse"><B>NREVERSE</B></A> DOC))))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> MY:DEFUN (NAME LAMBDA-LIST <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> DECLS-DOC-AND-FORMS<P>
<A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;ENVIRONMENT</B></A> ENV)<P>
(<A REL=DEFINITION HREF="../Body/m_multip.htm#multiple-value-bind"><B>MULTIPLE-VALUE-BIND</B></A> (FORMS DECLS DOC-STRINGS)<P>
(PARSE-BODY DECLS-DOC-AND-FORMS ENV)<P>
`(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> ,NAME ,BVL ,@DECLS ,@DOC-STRINGS ,@FORMS)))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> MY:LET (BINDINGS <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> DECLS-DOC-AND-FORMS<P>
<A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;ENVIRONMENT</B></A> ENV)<P>
(<A REL=DEFINITION HREF="../Body/m_multip.htm#multiple-value-bind"><B>MULTIPLE-VALUE-BIND</B></A> (FORMS DECLS DOC-STRINGS)<P>
(PARSE-BODY DECLS-DOC-AND-FORMS ENV)<P>
`(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> ,BINDINGS ,@FORMS)))<P>
<P>
...etc.<P>
<P>
<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> cannot be done this way, of course, since it is not a macro (or<P>
even a special form). Support for expanding declarations in a <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A><P>
would have to be provided either by using implementation-specific support<P>
(such as Zetalisp's ``<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> macros'') or by a workaround such as a<P>
macro like:<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> (LAMBDA-LIST <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> DECLS-DOC-AND-FORMS<P>
<A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;ENVIRONMENT</B></A> ENV)<P>
(<A REL=DEFINITION HREF="../Body/m_multip.htm#multiple-value-bind"><B>MULTIPLE-VALUE-BIND</B></A> (FORMS DECLS DOC-STRINGS)<P>
(PARSE-BODY DECLS-DOC-AND-FORMS ENV)<P>
`#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> ,BINDINGS ,@FORMS)))<P>
<P>
Note that unlike the other examples, <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> need not be (and in fact,<P>
may not be) in the &quot;MY&quot; package in order for this to work since the<P>
<A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> special form will generally only recognize LISP:LAMBDA.<P>
<P>
<B>Benefits:<P>
</B><P>
The efficiency of some tools may be improved.<P>
User macros which must do minor surgery on bodies of code will be<P>
easier to write.<P>
<P>
<B>Aesthetics:<P>
</B><P>
This change simplifies the semantics of the language slightly and<P>
probably tends to better support the assumptions of naive programmers<P>
writing macros.<P>
<P>
In some cases involving complicated extensions to declarations, it<P>
may be slightly harder to express such extensions in a modular way.<P>
Experience thus far has shown such cases to be rare, however.<P>
<P>
<B>Discussion:<P>
</B><P>
Symbolics took an in-house poll of people who take advantage of the<P>
feature and it was generally agreed that in most cases where this<P>
feature is used at all, that it would be just as easy to work around<P>
using the sample rewrite techniques cited above.<P>
<P>
Moon `credits' Pitman for (against some opposition) pushing this<P>
`feature' down everyone's throats in the original CL design process.<P>
Pitman admits this was an expensive mistake. Moon and Pitman support<P>
this change as an important simplification to the language.<P>
<P>
The cleanup committee unanimously endorsed this proposal.<P>
<P>
In discussion at the Nov-87 X3J13 meeting, Franz and Gold Hill<P>
mentioned that they use this feature a lot and were not entirely<P>
happy about its going away.<P>
<P>
</PRE>
<HR>
<A REL=NAVIGATOR HREF="../Front/StartPts.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Starting Points]" SRC="../Graphics/StartPts.gif" ALIGN=Bottom></A><A REL=TOC HREF="../Front/Contents.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Contents]" SRC="../Graphics/Contents.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Master.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Index]" SRC="../Graphics/Index.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Symbol.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Symbols]" SRC="../Graphics/Symbols.gif" ALIGN=Bottom></A><A REL=GLOSSARY HREF="../Body/26_a.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Glossary]" SRC="../Graphics/Glossary.gif" ALIGN=Bottom></A><A HREF="../Front/X3J13Iss.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Issues]" SRC="../Graphics/Issues.gif" ALIGN=Bottom></A><BR>
<A REL=COPYRIGHT HREF="../Front/Help.htm#Legal"><I>Copyright 1996-2005, LispWorks Ltd. All rights reserved.</I></A><P>
</BODY>
</HTML>