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

396 lines
26 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 COMPILER-LET-CONFUSION 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/iss065_w.htm">
<LINK REL=UP HREF="../Issues/iss066.htm">
<LINK REL=NEXT HREF="../Issues/iss067_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/iss065_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss066.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss067_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
<HR>
<H2>Issue COMPILER-LET-CONFUSION Writeup</H2>
<PRE><B>Issue:</B> <A HREF="iss066.htm">COMPILER-LET-CONFUSION</A><P>
<B>Forum:</B> Compiler<P>
<B>References:</B> CLtL p. 112<P>
Issue DEFINE-OPTIMIZER<P>
<B>Category:</B> CHANGE<P>
<B>Edit History:</B> V1, 27 Sep 1988, Sandra Loosemore (initial version)<P>
V2, 04 Oct 1988, Sandra Loosemore (add another example)<P>
V3, 31 Oct 1988, Sandra Loosemore (only proposal ELIMINATE)<P>
V4, 08 Jan 1989, Kent M. Pitman (new alternative)<P>
V5, 09 Jan 1989, Sandra Loosemore (discussion)<P>
V6, 08 Mar 1989, Sandra Loosemore (general updating)<P>
V7, 13 Mar 1989, Sandra Loosemore (fix bug from V6)<P>
V8, 23 Mar 1989, Sandra Loosemore (fix another bug, add<P>
to discussion)<P>
<B>Status:</B> Proposal ELIMINATE passed March 89.<P>
<P>
<B>Problem Description:<P>
</B><P>
The description of the COMPILER-LET special form in CLtL is confusing<P>
to many people. There are no examples provided to make it clear how it<P>
is supposed to be used. The only description which is offered is overly<P>
concrete, which has led to confusion about the intent of COMPILER-LET,<P>
and about its implementability.<P>
<P>
The intent of COMPILER-LET was to permit information to be communicated<P>
between macros by use of dynamic variables at macroexpansion time.<P>
It was not necessary to the intended uses of COMPILER-LET that such<P>
variables ever be bound at execution time. <P>
<P>
Unfortunately, probably because some implementations did not primitively<P>
support COMPILER-LET at the time CLtL was written, an exception was <P>
permitted to make COMPILER-LET `more or less work' in interpreters: <P>
the COMPILER-LET variables were permitted to be bound at execution time.<P>
The problem was further compounded by the fact that CLtL presented this<P>
exception as part of COMPILER-LET's contract rather than as an <P>
implementation note, and by the fact that no examples of actually using<P>
COMPILER-LET correctly are provided.<P>
<P>
One particular case where problems have resulted is a situation like<P>
(compiler-let ((*v* 1))<P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> () (m)))<P>
where M is a macro that refers to *V*. In some implementations, M is<P>
not macroexpanded until the dynamic extent of the *V* binding has<P>
ended.<P>
<P>
Subtle bugs can be introduced because of the different handling of the<P>
variable bindings in the interpreter and the compiler. In compiled<P>
code, the bindings are only lexically visible during the expansion of<P>
macros at compile time, while in interpreted code the bindings have<P>
dynamic scope and may also be seen during ordinary evaluation if<P>
evaluation and macroexpansion happen &quot;in parallel&quot;.<P>
<P>
Further compatibility problems can result from the value forms being<P>
evaluated in a null lexical environment in the compiler and the ordinary<P>
lexical environment in the interpreter.<P>
<P>
<B>Background and Analysis:<P>
</B><P>
It should be clear up front that COMPILER-LET is not computationally<P>
essential. Most (if not all) uses of it can be rewritten using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A><P>
or <A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A>.<P>
<P>
A typical use of COMPILER-LET might be:<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defpar.htm#defvar"><B>defvar</B></A> *local-type-declarations* '())<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> local-type-declare (declarations <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;body</B></A> forms)<P>
`(compiler-let ((*local-type-declarations* <P>
(<A REL=DEFINITION HREF="../Body/f_append.htm#append"><B>append</B></A> ',declarations *local-type-declarations*)))<P>
,@forms))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> typed-var (var)<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((<A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> (<A REL=DEFINITION HREF="../Body/f_assocc.htm#assoc"><B>assoc</B></A> var *local-type-declarations*)))<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> `(<A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> ,(<A REL=DEFINITION HREF="../Body/f_car_c.htm#cadr"><B>cadr</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A>) ,var) var)))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> f (x y)<P>
(local-type-declare ((x <A REL=DEFINITION HREF="../Body/t_fixnum.htm#fixnum"><B>fixnum</B></A>) (y <A REL=DEFINITION HREF="../Body/a_float.htm#float"><B>float</B></A>))<P>
(+ (typed-var x) (typed-var y))))<P>
<P>
<P>
The same thing could be accomplished using MACROLET:<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> local-type-declare (declarations <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;body</B></A> forms)<P>
(local-type-declare-aux declarations forms))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> typed-var (var) var)<P>
<P>
(<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_defun.htm#defun"><B>defun</B></A> local-type-declare-aux (declarations forms)<P>
`(<A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>macrolet</B></A> ((typed-var (var)<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((<A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> (<A REL=DEFINITION HREF="../Body/f_assocc.htm#assoc"><B>assoc</B></A> var ',declarations)))<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> `(<A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> ,(<A REL=DEFINITION HREF="../Body/f_car_c.htm#cadr"><B>cadr</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A>) ,var) var)))<P>
(local-type-declare (new-declarations <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;body</B></A> new-forms)<P>
(local-type-declare-aux<P>
(<A REL=DEFINITION HREF="../Body/f_append.htm#append"><B>append</B></A> new-declarations ',declarations)<P>
new-forms)))<P>
,@forms)))<P>
<P>
<P>
A further alternative would be to use <A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A> (this particular<P>
implementation assumes that issue <A HREF="iss104.htm">DEFINING-MACROS-NON-TOP-LEVEL</A> passes):<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((temp (<A REL=DEFINITION HREF="../Body/f_gensym.htm#gensym"><B>gensym</B></A>)))<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> local-type-declare (declarations <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;body</B></A> forms <A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;environment</B></A> env)<P>
`(<A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>symbol-macrolet</B></A> ((,temp ',(<A REL=DEFINITION HREF="../Body/f_append.htm#append"><B>append</B></A> declarations<P>
(symbol-macro-value temp env))))<P>
,@forms))<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>defmacro</B></A> typed-var (var <A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;environment</B></A> env)<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((<A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> (<A REL=DEFINITION HREF="../Body/f_assocc.htm#assoc"><B>assoc</B></A> var (symbol-macro-value temp env))))<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A> `(<A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> ,(<A REL=DEFINITION HREF="../Body/f_car_c.htm#cadr"><B>cadr</B></A> <A REL=DEFINITION HREF="../Body/a_type.htm#type"><B>type</B></A>) ,var) var)))<P>
)<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> symbol-macro-value (<A REL=DEFINITION HREF="../Body/t_symbol.htm#symbol"><B>symbol</B></A> env <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;optional</B></A> default)<P>
(<A REL=DEFINITION HREF="../Body/m_multip.htm#multiple-value-bind"><B>multiple-value-bind</B></A> (expansion macro-p) (<A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand"><B>macroexpand</B></A> <A REL=DEFINITION HREF="../Body/t_symbol.htm#symbol"><B>symbol</B></A> env)<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> macro-p (<A REL=DEFINITION HREF="../Body/f_eval.htm#eval"><B>eval</B></A> expansion) default)))<P>
<P>
<P>
Opinion is divided as to which is more understandable. Some<P>
people find the COMPILER-LET idiom more understandable (assuming that<P>
it can be made to work consistently in compiled and interpreted<P>
code), while others find it just as natural to use <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> or <P>
<A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A>.<P>
<P>
The issues are these:<P>
<P>
- Is it possible to implement COMPILER-LET in a usefully consistent<P>
way in all implementations?<P>
<P>
- Are the benefits of providing a useful and compatible implementation<P>
of COMPILER-LET worth any associated cost?<P>
<P>
Two proposals are presented below:<P>
<P>
- Option REPAIR argues that COMPILER-LET provides interesting<P>
functionality that can be implemented in a manner that is usefully<P>
consistent across implementations, and that the associated cost<P>
is low enough for it to be worthwhile to do so.<P>
<P>
- Option ELIMINATE argues that COMPILER-LET complicates the language<P>
and that providing this construct is not worth the associated <P>
implementation cost.<P>
<P>
<P>
<B>Proposal (COMPILER-LET-CONFUSION:REPAIR):<P>
</B><P>
Strike the existing definition of COMPILER-LET. Redefine it as follows:<P>
<P>
COMPILER-LET [Special form]<P>
<P>
COMPILER-LET is similar to <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A>, but it always makes special <P>
bindings and makes those bindings visible only during <P>
macroexpansion of forms in the body, not during the runtime<P>
execution of those forms. <P>
<P>
If proposal DEFINE-OPTIMIZER:NEW-FACILITY is accepted, then<P>
optimizer functions are also executed in a dynamic environment<P>
in which COMPILER-LET bindings are visible.<P>
<P>
The intent is that some macros might <A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand"><B>macroexpand</B></A> into calls to<P>
COMPILER-LET in which the body would the contain references to<P>
macros which access the variables in the COMPILER-LET.<P>
<P>
The initial value forms of the bindings, if any, are always <P>
evaluated in a null lexical context, regardless of whether the<P>
COMPILER-LET expression is being interpreted or compiled.<P>
<P>
The initial value forms of the bindings, if any, are evaluated in<P>
a dynamic context where the bindings of any lexically enclosing<P>
COMPILER-LET are visible, and where dynamic execution-time <P>
environment may or may not be visible.<P>
<P>
Implementation Note: Permitting the execution-time dynamic<P>
environment to be visible when initializing COMPILER-LET variables<P>
is a concession to some interpreters which may have to do this in<P>
order to keep the cost down. Where feasible, implementors should<P>
try not to make the runtime environment visible.<P>
<P>
Rationale:<P>
<P>
This gives a consistent description of COMPILER-LET which separates<P>
issues of intent from those of implementation in a way that makes it<P>
possible for portable code to make serious use of it, and which does<P>
not force gratuitous incompatibilities between interpreters and<P>
compilers.<P>
<P>
This description of COMPILER-LET can be implemented without undue<P>
cost by all implementations. See &quot;Cost to Implementors&quot; for details.<P>
<P>
Cost to Implementors:<P>
<P>
Modest, but nontrivial in some implementations.<P>
<P>
In compiled code, and in interpreters doing a one-time semantic<P>
prepass, it should be fairly easy for COMPILER-LET to cause the <P>
variables to get bound (using <A REL=DEFINITION HREF="../Body/s_progv.htm#progv"><B>PROGV</B></A>) during semantic analysis.<P>
<P>
In interpreters which do not do a semantic-prepass, it is necessary<P>
to fully <A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand"><B>macroexpand</B></A> the body. Assuming the presence of a<P>
SYSTEM::MACROEXPAND-ALL primitive, the definition of COMPILER-LET<P>
could look like:<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> COMPILER-LET (BINDINGS <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> FORMS <A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;ENVIRONMENT</B></A> ENV)<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> BINDINGS ;; Assure no non-atom bindings<P>
(<A REL=DEFINITION HREF="../Body/f_mapc_.htm#mapcar"><B>MAPCAR</B></A> #'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> (BINDING) <P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>IF</B></A> (<A REL=DEFINITION HREF="../Body/a_atom.htm#atom"><B>ATOM</B></A> BINDING) (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> BINDING) BINDING))<P>
BINDINGS))<P>
(<A REL=DEFINITION HREF="../Body/s_progv.htm#progv"><B>PROGV</B></A> (<A REL=DEFINITION HREF="../Body/f_mapc_.htm#mapcar"><B>MAPCAR</B></A> #'<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> BINDINGS)<P>
(<A REL=DEFINITION HREF="../Body/f_mapc_.htm#mapcar"><B>MAPCAR</B></A> #'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> (BINDING) (<A REL=DEFINITION HREF="../Body/f_eval.htm#eval"><B>EVAL</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#cadr"><B>CADR</B></A> BINDING))) BINDINGS)<P>
(SYSTEM::MACROEXPAND-ALL `(<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>PROGN</B></A> ,@FORMS) ENV)))<P>
This reduces the problem of writing a program capable of doing a<P>
full macroexpansion. Many systems already have such a facility.<P>
Pitman wrote such a facility in Cloe Runtime in order support <P>
<A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A> (before it was christened a special form); it was<P>
about 750 lines of relatively straightforward, well-commented code.<P>
<P>
Cost to Users:<P>
<P>
Code currently depending on this feature is either non-existent or<P>
already not portable (due to wide variation in implementation <P>
strategy for COMPILER-LET).<P>
<P>
Most users will probably be happy for any interpretation which offers<P>
them a future shot at portability.<P>
<P>
Some users have indicated they dislike interpreters which do a semantic<P>
prepass, because they like to be able to dynamically redefine macros<P>
while debugging.<P>
<P>
<P>
<B>Proposal (COMPILER-LET-CONFUSION:ELIMINATE):<P>
</B><P>
Remove COMPILER-LET from the language.<P>
<P>
Rationale:<P>
<P>
Some people think that having one less special form would simplify the<P>
language. The revised COMPILER-LET semantics, which <A REL=DEFINITION HREF="../Body/f_provid.htm#require"><B>require</B></A><P>
COMPILER-LET to make special bindings which are only visible during<P>
expansion of macros which appear lexically within its body, are<P>
not shared by any other feature in the language, and <A REL=DEFINITION HREF="../Body/f_provid.htm#require"><B>require</B></A> a<P>
fairly complex implementation technique. There are other<P>
constructs which are strictly lexical that can be readily used<P>
to solve the same kinds of problems that COMPILER-LET is intended to<P>
be used for.<P>
<P>
Cost to Implementors:<P>
<P>
Minimal. Implementations could continue to support COMPILER-LET as<P>
an extension.<P>
<P>
Cost to Users:<P>
<P>
Code currently depending on this feature is either non-existent or<P>
already not portable (due to wide variation in implementation <P>
strategy for COMPILER-LET).<P>
<P>
People who use COMPILER-LET would have to rewrite their programs to use<P>
some other construct. As discussed above, most uses of COMPILER-LET<P>
for communication between macros can be handled using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> or<P>
<A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A>, though some perspicuity may be lost in the process.<P>
<P>
<P>
<B>Current Practice:<P>
</B> <P>
Some implementations have implemented the description in CLtL. <P>
Users of those implementations (quite reasonably) can't figure how to <P>
use COMPILER-LET and so don't use it much.<P>
<P>
Some implementations whose interpreters include a preprocessor to<P>
expand all macros have already implemented something similar to proposal<P>
COMPILER-LET-CONFUSION:REPAIR. Users of such implementations<P>
probably use COMPILER-LET somewhat more often since it has an<P>
intelligible behavior, but their code is not portable since it relies<P>
on behaviors which are either contrary to or not guaranteed by CLtL.<P>
<P>
<B>Benefits:<P>
</B><P>
Either way, a potential area of incompatibility between compiled and<P>
interpreted code would be eliminated.<P>
<P>
Either way, a potential area of portability trouble would be very<P>
drastically reduced (in the case of the REPAIR option) or eliminated<P>
(in the case of the ELIMINATE option).<P>
<P>
<B>Discussion:<P>
</B><P>
Pitman strongly favors COMPILER-LET-CONFUSION:REPAIR. He argues <P>
against the idea of using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> instead of COMPILER-LET, saying:<P>
<P>
This is a little misleading because it's like saying you can<P>
do without <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> given that you have <A REL=DEFINITION HREF="../Body/s_flet_.htm#flet"><B>FLET</B></A>. You can, but you lose some things<P>
in the process:<P>
<P>
Just as rewriting a <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> using <A REL=DEFINITION HREF="../Body/s_flet_.htm#flet"><B>FLET</B></A> might slow your computation, so too<P>
a rewrite of COMPILER-LET using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> might slow things down. However,<P>
compilation speed is generally not weighted as heavily as execution speed<P>
by many people, so the loss of speed here may not be as important.<P>
<P>
Just as rewriting a <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> using <A REL=DEFINITION HREF="../Body/s_flet_.htm#flet"><B>FLET</B></A> might obscure the simplicity of your<P>
intent, so too rewriting COMPILER-LET using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> might obscure your<P>
intent. You'd probably get used to recognizing idioms if you used it often<P>
enough. Certainly this would be true if you didn't have <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A>. However,<P>
COMPILER-LET is used less often, so not having it would mean that the<P>
code you wrote instead would be much harder to read because people<P>
wouldn't have the necessary familiarity with the idioms involved and so<P>
wouldn't always understand them.<P>
<P>
Sandra Loosemore responds:<P>
<P>
The argument that using <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> is more inefficient than COMPILER-LET<P>
is questionable. Both of the suggested implementation techniques for<P>
COMPILER-LET involve considerable overhead.<P>
<P>
If COMPILER-LET were not part of the language, people wouldn't think in<P>
terms of rewriting COMPILER-LETs as MACROLETs; instead, they'd think of<P>
how to use <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> in the first place to solve their problems. This<P>
is what people who now use implementations with broken COMPILER-LETs<P>
already do. Since <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> is now used much more frequently than<P>
COMPILER-LET, that argues that people are much more familiar with <P>
<A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A> idioms than COMPILER-LET idioms.<P>
<P>
Also, note that the intent of the revised COMPILER-LET definition is<P>
to make the binding only lexically visible within the body. Using<P>
special binding for this purpose is troublesome. Both the <A REL=DEFINITION HREF="../Body/s_flet_.htm#macrolet"><B>MACROLET</B></A><P>
and <A REL=DEFINITION HREF="../Body/s_symbol.htm#symbol-macrolet"><B>SYMBOL-MACROLET</B></A> solutions are completely lexical and avoid all<P>
the problems associated with special binding.<P>
<P>
Glenn Burke thinks it needs to be emphasized that the code-walker<P>
mentioned in the REPAIR proposal does not need to be portable. He<P>
says:<P>
<P>
The present wording makes it sound like a piece of cake to do with<P>
portable code, when the reality is that a good fraction of CL cleanup<P>
effort has involved the lack of capability of producing such a beast.<P>
Without one or more of a number of proposals being accepted, a fully<P>
correct portable code walker cannot be built, in my belief.<P>
<P>
I object to the flippant attitude of just &quot;presupposing&quot; this<P>
&quot;trivial&quot; function which &quot;we know how to do&quot;.<P>
<P>
We have considered a number of other options on this issue, including<P>
a variety of proposals that would redefine COMPILER-LET to store<P>
information about the variable bindings in the lexical environment, and<P>
either having <A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand-1"><B>MACROEXPAND-1</B></A> make the special bindings or <A REL=DEFINITION HREF="../Body/f_provid.htm#provide"><B>provide</B></A> a<P>
function which could be used to access them directly.<P>
<P>
Kent Pitman says:<P>
People have suggested that if it comes to making an incompatible change<P>
on this one, it's probably better to just remove the feature and let<P>
people continue to <A REL=DEFINITION HREF="../Body/f_provid.htm#provide"><B>provide</B></A> it compatibly where they think it's useful.<P>
Even though I think the COMPILER-SYMBOL-VALUE thing is technically<P>
doable, I find myself swayed by arguments that it's not the correct<P>
avenue for us to pursue at this time.<P>
<P>
David Moon says:<P>
I think COMPILER-LET-CONFUSION:REPAIR should be split into four proposals.<P>
First, one that gives the general framework for repairing but doesn't<P>
say anything about how the interpreter implements COMPILER-LET, other<P>
than to say that an additional proposal is needed to cover that. Then<P>
three proposals for how the interpreter implements COMPILER-LET:<P>
(1) The interpreter always does a &quot;semantic pre-pass&quot; like the compiler.<P>
(2) The interpreter expands all macros inside COMPILER-LET before<P>
evaluating any of the code inside COMPILER-LET.<P>
(3) COMPILER-LET passes the variable bindings to <A REL=DEFINITION HREF="../Body/f_mexp_.htm#macroexpand-1"><B>MACROEXPAND-1</B></A><P>
through the lexical environment, and the time when the interpreter<P>
expands macros is not changed.<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>