[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Issue: DECLARATION-SCOPE
- To: Pavel.pa@Xerox.COM, SMH%Franz.uucp@berkeley.edu
- Subject: Issue: DECLARATION-SCOPE
- From: Masinter.pa@Xerox.COM
- Date: 19 Nov 87 17:59 PST
- Cc: cl-cleanup@Sail.stanford.edu
My notes from Denver are a little fuzzy on this issue; I think what they
mean is that you might be convinced to write up a proposal on these
issues...
I've started using our common-lisp mailing list index again, and
retrieved some of the previous mail on this subject.
----- Begin Forwarded Messages -----
Return-Path: <spar!schoen@decwrl.dec.com>
Received: from decwrl.dec.com by Xerox.COM ; 08 JUL 87 14:18:08 PDT
Received: by decwrl.dec.com (5.54.3/4.7.34)
id AA25408; Wed, 8 Jul 87 14:17:34 PDT
Received: By spar.SPAR.CAS.SLB.COM (from gyro.SPAR.CAS.SLB.COM)
id AA00706; Wed, 8 Jul 87 10:59:57 PDT
Return-Path: <schoen@gyro>
Received: By gyro.SPAR.CAS.SLB.COM
id AA09848; Wed, 8 Jul 87 10:59:31 PDT
Date: Wed, 8 Jul 87 10:59:31 PDT
From: Eric Schoen <spar!schoen@decwrl.dec.com>
Message-Id: <8707081759.AA09848@gyro.SPAR.CAS.SLB.COM>
To: masinter.pa
Subject: Common Lisp cleanup
Larry:
I think I have a submission for the cleanup committee, but I've lost
your
submission format. I'll try to provide the information you want.
Let's call this issue LET:SPECIAL-SCOPE or somesuch. Here's the crux of
the
problem. Consider a LET expression like:
(let ((a <foo>))
(declare (special a))
(bar))
I've macroexpanded this example under Franz, Lucid, TI, and Symbolics
Common
Lisps. The first three macroexpand to:
((lambda nil
(declare (special a))
((lambda (a)
(declare (special a))
(bar))
<foo>)))
The last expands to:
((lambda nil
((lambda (a)
(declare (special a))
(bar))
<foo>)))
These are exactly equivalent unless <foo> happens to be the variable a.
Under
TI, Lucid, and Franz's implementations, the interior a gets bound to the
dynamic binding of a as of the time the entire expression is entered.
Under
Symbolics, the interior a gets bound to the lexical value of a when the
expression is entered (assuming there is a lexically apparent binding of
a).
So which is the proper treatment of the special declaration? I tend to
believe Symbolics is doing it correctly, but then why do so many other
implementations do it differently?
This came up when I was trying something like the following:
(setq c (let ((a 1))
#'(lambda (function &rest args)
(let ((a a))
(declare (special a))
(apply function args)))))
(funcall c 'eval 'a)
When you do the funcall with a unbound globally, the TI, Franz, and
Lucid
implementations signal an error because a is unbound, whereas the
Symbolics
implementation returns 1. The idea in this example is to return a
closure
which captures the lexical value of a variable and makes it available
dynamically when the closure is applied. I tried simpler approaches
like
locally declaring a special within the closure, but these failed on all
implementations.
I imagine the cost of fixing all implementations to behave like the
Symbolics
implementation would be very low, since it's only a matter of changing
the
macro definition of let. The impact ought to be minor, since this is a
very
unusual situation. I also think it deserves a clarification in the
silver
book.
Eric
----- Next Message -----
Originator: @SAIL.STANFORD.EDU:Moon%STONY-BROOK.SCRC.Symbolics:COM:Xerox
Date: 18 Aug 87 14:14
From: Moon%STONY-BROOK.SCRC.Symbolics:COM:Xerox
Subject: FLET & declarations
In-Reply-to: <12327146435.14.GZ@OZ.AI.MIT.EDU>
To: GZ%OZ.AI.MIT.EDU%XX.LCS.MIT:EDU:Xerox
cc: common-lisp%SAIL.STANFORD:EDU:Xerox
GVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGV
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: FLET & declarations
To: GZ%OZ.AI.MIT.EDU@XX.LCS.MIT.EDU
cc: common-lisp@SAIL.STANFORD.EDU
In-Reply-To: <12327146435.14.GZ@OZ.AI.MIT.EDU>
Return-Path: <@SAIL.STANFORD.EDU:Moon@STONY-BROOK.SCRC.Symbolics.COM>
Redistributed: Xerox-Common-Lispâ??.x
Received: from SAIL.STANFORD.EDU by Xerox.COM ; 18 AUG 87 14:14:29 PDT
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 18
Aug 87 13:28:28 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by
STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 215806; Tue
18-Aug-87 16:28:17 EDT
Original-Date: Tue, 18 Aug 87 16:27 EDT
Message-ID: <870818162759.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
GVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGV
Date: Mon 17 Aug 87 03:57:47-EDT
From: GZ%OZ.AI.MIT.EDU@XX.LCS.MIT.EDU
Are 'pervasive' declarations in FLET supposed to apply to the
function bodies?
E.g.
(flet ((foo () x)) ;Is this x special?
(declare (special x))
...)
(flet ((foo () (foo) ...)) ;Does this call to (foo) return a
fixnum?
(declare (function foo () fixnum))
...)
(flet ((foo () (foo 17))) ;Is (foo 17) inline?
(declare (inline foo))
...)
CLtL does not permit DECLARE to be used in that position (see p.113).
I believe it has been proposed to change that, although I couldn't
find a copy of the proposal in my rather disorganized files. I would
argue that the paragraph in the middle of page 155 of CLtL supports
the position that when this extension is made, the pervasive
declarations
should apply to the function bodies.
Note that the FUNCTION declaration used in your middle example is not
pervasive. Since you use FLET rather than LABELS, this declaration
would not apply to the call to FOO within the body of FOO. It's a
different FOO.
The INLINE declaration is said by CLtL to be pervasive, however I
believe that to be a bug since it makes it unclear which of the two
FOOs in your example it refers to. Perhaps it refers to both.
Anyone putting together a proposal to clean up the specification of
declarations in Common Lisp ought to address the issues raised by
your question.
----- End Forwarded Messages -----
05-Jul-86 1654 Pavel.pa@Xerox.COM DECLARE SPECIAL Considered Confusing
Received: from XEROX.COM by SU-AI.ARPA with TCP; 5 Jul 86 16:54:09 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 05 JUL 86 16:54:24 PDT
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
Subject: DECLARE SPECIAL Considered Confusing
To: Common-Lisp@SU-AI.ARPA
Message-ID: <860705-165424-2715@Xerox>
I have a question concerning some ambiguity in the description of the
scope of a special declaration inside a LET. Consider this code:
(setq foo 6)
(let ((foo 7))
(let ((foo (1+ foo)))
(declare (special foo))
foo))
Both Symbolics and CLISP return 8 for this, but VAXLISP returns 7.
Clearly, the question is whether or not the special declaration covers
the init-form of the enclosing LET or just the bindings themselves.
According to the ``nonsense'' example in CLtL, page 155, the reference
to ``foo'' in the call to 1+ should be special. The GLS clarification
for page 159, however, seems to support a different philosophy:
``(*) 159 Clarify that in the following example
(defun foo (x)
(declare (inline bar))
(bar x) ; first
(flet ((bar (z) (bar (+ z 1)))) ; second
(bar x)) ; third
(bar x) ; fourth the first, second and
fourth calls to BAR are affected by the INLINE declaration, but not the
third one.''
This seems to support the view that the init-form of a binding is in a
scope outside of that of the binding itself and the body of the LET (or
FLET or ...). I prefer this view.
I would like to propose the following rule for the scope of declarations
in binding forms:
``A declaration in a binding form (such as LET) affects the body of the
form and the bindings themselves. It does not affect the init-forms for
the bindings; they are in the same scope as the binding form as a
whole.''
This rule has the advantage (over the rule given for the nonsense
example) that the scope of the declarations is the same as the scope of
the bindings. Thus, for the nonsense example:
(defun nonsense (k x z)
(foo z x) ;First call to foo
(let ((j (foo k x)) ;Second call to foo
(x (* k k)))
(declare (inline foo)
(special x z))
(foo x j z))) ;Third call to foo
the inline declaration affects only the third call to foo (not the
second) and only the references to x and z in the third call to foo are
special (not the reference to x in the second call).
There would be only two exceptions to this rule:
-- In a LABELS binding, references in the definitions of the functions
to the very functions being bound would be affected by any declarations
affecting the bindings themselves. This makes sense because of the
recursive quality of the binding.
-- The PROCLAIM function establishes pervasive declarations, covering
all bindings of and references to the symbols named. Such declarations
can, of course, be countermanded by local declarations or later
proclamations.
What do people think? It would appear that some implementations already
work this way.
Pavel Curtis
Xerox AIS
!
07-Jul-86 0704 DCP@QUABBIN.SCRC.Symbolics.COM DECLARE SPECIAL
Considered Confusing
Received: from SCRC-QUABBIN.ARPA by SU-AI.ARPA with TCP; 7 Jul 86
07:04:50 PDT
Received: from FIREBIRD.SCRC.Symbolics.COM by QUABBIN.SCRC.Symbolics.COM
via CHAOS with CHAOS-MAIL id 16663; Mon 7-Jul-86 10:03:32 EDT
Date: Mon, 7 Jul 86 10:03 EDT
From: David C. Plummer <DCP@QUABBIN.SCRC.Symbolics.COM>
Subject: DECLARE SPECIAL Considered Confusing
To: Pavel.pa@Xerox.COM, Common-Lisp@SU-AI.ARPA
In-Reply-To: <860705-165424-2715@Xerox>
Message-ID: <860707100308.8.DCP@FIREBIRD.SCRC.Symbolics.COM>
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
What do people think? It would appear that some implementations
already
work this way.
I agree. Consider LET to be a macro that turns into LAMBDA:
(let ((foo (1+ foo)))
(declare (special foo))
foo)
=> ((lambda (foo)
(declare (special foo))
foo)
(1+ foo)) [I think this is what MacLisp actually did (does?).] The
scoping here is clear: the foo in (1+ foo) is outside the scope of the
declaration.
!
Received: from [192.10.41.41] by SU-AI.ARPA with TCP; 7 Jul 86 18:15:31
PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by
ELEPHANT-BUTTE.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 36962;
Mon 7-Jul-86 20:58:58 EDT
Date: Mon, 7 Jul 86 20:59 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: DECLARE SPECIAL Considered Confusing
To: Pavel.pa@Xerox.COM
cc: Common-Lisp@SU-AI.ARPA
In-Reply-To: <860705-165424-2715@Xerox>
Message-ID: <860707205952.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
I do not wish to defend the current choice of declaration-scoping rules
in Common Lisp as the best or only choice, but I do wish to clarify what
the rules are in the language as it is currently defined. It wouldn't
bother me if a future revision of the language adopted simpler rules,
provided they were truly (not just superficially) simpler.
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
I have a question concerning some ambiguity in the description of
the
scope of a special declaration inside a LET. Consider this code:
(setq foo 6)
(let ((foo 7))
(let ((foo (1+ foo)))
(declare (special foo))
foo))
Both Symbolics and CLISP return 8 for this, but VAXLISP returns 7.
VAXLISP is incorrect here. The SPECIAL declaration is pervasive for
references (but non-pervasive for bindings). Because SPECIAL is
pervasive for references it affects the reference to foo inside 1+.
Clearly, the question is whether or not the special declaration
covers
the init-form of the enclosing LET or just the bindings themselves.
According to the ``nonsense'' example in CLtL, page 155, the
reference
to ``foo'' in the call to 1+ should be special. The GLS
clarification
for page 159, however, seems to support a different philosophy:
``(*) 159 Clarify that in the following example
(defun foo (x)
(declare (inline bar))
(bar x) ; first
(flet ((bar (z) (bar (+ z 1)))) ; second
(bar x)) ; third
(bar x) ; fourth
the first, second and fourth calls to BAR are affected by the INLINE
declaration, but not the third one.''
This seems to support the view that the init-form of a binding is in
a
scope outside of that of the binding itself and the body of the LET
(or
FLET or ...). I prefer this view.
The scoping of variables (and FLET functions) is different from the
scoping of pervasive declarations. There is no analogy between this
example and your previous one, because the INLINE declaration is not
attached to a binding, but the SPECIAL declaration is attached to a
binding. All that's shown by this clarification is that INLINE, just
like SPECIAL, is shadowed by an occurrence of another binding of the
same name inside its scope.
Incidentally, the bottom of p.154 says that SPECIAL is the only
declaration that falls into both classes, but I think INLINE is really
in the same category. It concerns a particular binding, but can also be
used in the absence of a binding and is pervasive for references, just
like SPECIAL.
I would like to propose the following rule for the scope of
declarations
in binding forms:
``A declaration in a binding form (such as LET) affects the body of
the
form and the bindings themselves. It does not affect the init-forms
for
the bindings; they are in the same scope as the binding form as a
whole.''
This rule has the advantage (over the rule given for the nonsense
example) that the scope of the declarations is the same as the scope
of
the bindings. Thus, for the nonsense example:
(defun nonsense (k x z)
(foo z x) ;First call to foo
(let ((j (foo k x)) ;Second call to foo
(x (* k k)))
(declare (inline foo)
(special x z))
(foo x j z))) ;Third call to foo
the inline declaration affects only the third call to foo (not the
second) and only the references to x and z in the third call to foo
are
special (not the reference to x in the second call).
There would be only two exceptions to this rule:
-- In a LABELS binding, references in the definitions of the
functions
to the very functions being bound would be affected by any
declarations
affecting the bindings themselves. This makes sense because of the
recursive quality of the binding.
-- The PROCLAIM function establishes pervasive declarations,
covering
all bindings of and references to the symbols named. Such
declarations
can, of course, be countermanded by local declarations or later
proclamations.
What about declarations inside the body of DEFUN? With your rules I
cannot see how a declaration could ever affect the default value forms
for &optional, &key, and &aux variables. And what about declarations
inside the body of a LET*? The scoping of ones attached to variables is
fairly obvious, but what about ones not attached to variables?
We went all through this during the design of Common Lisp (I think the
discussion is available online) and the current rules resulted. Given
that we must have DECLARE at all (a point which you should not
necessarily be willing to concede), the current rules seem to work more
consistently than the alternatives that were considered.
!
Received: from BBNG.ARPA by SU-AI.ARPA with TCP; 7 Jul 86 19:45:22 PDT
Date: 7 Jul 1986 22:44-EDT
Sender: NGALL@G.BBN.COM
Subject: Re: DECLARE SPECIAL Considered Confusing
From: NGALL@G.BBN.COM
To: Moon@SCRC-STONY-BROOK.ARPA
Cc: Pavel.pa@XEROX.COM, Common-Lisp@SU-AI.ARPA
Message-ID: <[G.BBN.COM] 7-Jul-86 22:44:13.NGALL>
In-Reply-To: <860707205952.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Mon, 7 Jul 86 20:59 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
To: Pavel.pa@Xerox.COM
Subject: DECLARE SPECIAL Considered Confusing
In-Reply-To: <860705-165424-2715@Xerox>
Message-ID: <860707205952.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
...
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
I have a question concerning some ambiguity in the description of the
scope of a special declaration inside a LET. Consider this code:
(setq foo 6)
(let ((foo 7))
(let ((foo (1+ foo)))
(declare (special foo))
foo))
Both Symbolics and CLISP return 8 for this, but VAXLISP returns 7.
VAXLISP is incorrect here. The SPECIAL declaration is pervasive for
references (but non-pervasive for bindings). Because SPECIAL is
pervasive for references it affects the reference to foo inside 1+.
I don't wish to add to the confusion here, but my reading of pg 155
agrees with VaxLisp: the above example should return 7. The outermost
LET binds a lexical var. named foo that is never referenced. The
special declaration in the inner LET affects the variable being bound by
the LET (foo) and it affects the reference to foo in the explicit body
(i.e. the last reference to foo) and the reference to foo in the
init-form in the inner LET is also special. The global value of foo is
6, and 6 + 1 = 7.
-- Nick
!
Received: from SCRC-QUABBIN.ARPA by SU-AI.ARPA with TCP; 7 Jul 86
20:15:02 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by
QUABBIN.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 17091; Mon
7-Jul-86 23:13:40 EDT
Date: Mon, 7 Jul 86 23:13 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: DECLARE SPECIAL Considered Confusing
To: Pavel.pa@Xerox.COM
cc: Common-Lisp@SU-AI.ARPA
In-Reply-To: <860705-165424-2715@Xerox>
Supersedes: <860707205952.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Message-ID: <860707231340.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
I do not wish to defend the current choice of declaration-scoping rules
in Common Lisp as the best or only choice, but I do wish to clarify what
the rules are in the language as it is currently defined. It wouldn't
bother me if a future revision of the language adopted simpler rules,
provided they were truly (not just superficially) simpler.
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
I have a question concerning some ambiguity in the description of
the
scope of a special declaration inside a LET. Consider this code:
(setq foo 6)
(let ((foo 7))
(let ((foo (1+ foo)))
(declare (special foo))
foo))
Both Symbolics and CLISP return 8 for this, but VAXLISP returns 7.
VAXLISP is correct here. The SPECIAL declaration is pervasive for
references (but non-pervasive for bindings). Because SPECIAL is
pervasive for references it affects the reference to foo inside 1+.
I apologize for the incorrect earlier version of this message that said
that VAXLISP was incorrect here. I didn't mean to add to the confusion;
it must have been a Freudian slip.
Incidentally, the incorrect result returned here by the Symbolics
implementation is a (poorly) documented incompatibility with Common Lisp
that will be fixed at some time in the future.
Clearly, the question is whether or not the special declaration
covers
the init-form of the enclosing LET or just the bindings themselves.
According to the ``nonsense'' example in CLtL, page 155, the
reference
to ``foo'' in the call to 1+ should be special. The GLS
clarification
for page 159, however, seems to support a different philosophy:
``(*) 159 Clarify that in the following example
(defun foo (x)
(declare (inline bar))
(bar x) ; first
(flet ((bar (z) (bar (+ z 1)))) ; second
(bar x)) ; third
(bar x) ; fourth
the first, second and fourth calls to BAR are affected by the INLINE
declaration, but not the third one.''
This seems to support the view that the init-form of a binding is in
a
scope outside of that of the binding itself and the body of the LET
(or
FLET or ...). I prefer this view.
The scoping of variables (and FLET functions) is different from the
scoping of pervasive declarations. There is no analogy between this
example and your previous one, because the INLINE declaration is not
attached to a binding, but the SPECIAL declaration is attached to a
binding. All that's shown by this clarification is that INLINE, just
like SPECIAL, is shadowed by an occurrence of another binding of the
same name inside its scope.
Incidentally, the bottom of p.154 says that SPECIAL is the only
declaration that falls into both classes, but I think INLINE is really
in the same category. It concerns a particular binding, but can also be
used in the absence of a binding and is pervasive for references, just
like SPECIAL.
I would like to propose the following rule for the scope of
declarations
in binding forms:
``A declaration in a binding form (such as LET) affects the body of
the
form and the bindings themselves. It does not affect the init-forms
for
the bindings; they are in the same scope as the binding form as a
whole.''
This rule has the advantage (over the rule given for the nonsense
example) that the scope of the declarations is the same as the scope
of
the bindings. Thus, for the nonsense example:
(defun nonsense (k x z)
(foo z x) ;First call to foo
(let ((j (foo k x)) ;Second call to foo
(x (* k k)))
(declare (inline foo)
(special x z))
(foo x j z))) ;Third call to foo
the inline declaration affects only the third call to foo (not the
second) and only the references to x and z in the third call to foo
are
special (not the reference to x in the second call).
There would be only two exceptions to this rule:
-- In a LABELS binding, references in the definitions of the
functions
to the very functions being bound would be affected by any
declarations
affecting the bindings themselves. This makes sense because of the
recursive quality of the binding.
-- The PROCLAIM function establishes pervasive declarations,
covering
all bindings of and references to the symbols named. Such
declarations
can, of course, be countermanded by local declarations or later
proclamations.
What about declarations inside the body of DEFUN? With your rules I
cannot see how a declaration could ever affect the default value forms
for &optional, &key, and &aux variables. And what about declarations
inside the body of a LET*? The scoping of ones attached to variables is
fairly obvious, but what about ones not attached to variables?
We went all through this during the design of Common Lisp (I think the
discussion is available online) and the current rules resulted. Given
that we must have DECLARE at all (a point which you should not
necessarily be willing to concede), the current rules seem to work more
consistently than the alternatives that were considered.
!
Received: from CS.UCL.AC.UK by SU-AI.ARPA with TCP; 8 Jul 86 13:54:24
PDT
Received: from aiva.edinburgh.ac.uk by 44d.Cs.Ucl.AC.UK via Janet with
NIFTP
id a002506; 7 Jul 86 19:30 BST
From: Jeff Dalton <jeff%aiva.edinburgh.ac.uk@Cs.Ucl.AC.UK>
Date: Mon, 7 Jul 86 19:27:20 -0100
Message-Id: <1672.8607071827@aiva.ed.ac.uk>
To: Common-Lisp@su-ai.arpa, DCP@scrc-quabbin.arpa, Pavel.pa@xerox.com
Subject: Re: DECLARE SPECIAL Considered Confusing
Date: Mon, 7 Jul 86 10:03 EDT
From: "David C. Plummer" <DCP@arpa.scrc-quabbin>
Subject: DECLARE SPECIAL Considered Confusing
Date: 5 Jul 86 16:54 PDT
From: Pavel.pa@Xerox.COM
What do people think? It would appear that some implementations
already
work this way.
I agree. Consider LET to be a macro that turns into LAMBDA:
(let ((foo (1+ foo)))
(declare (special foo))
foo)
=> ((lambda (foo)
(declare (special foo))
foo)
(1+ foo))
[I think this is what MacLisp actually did (does?).] The scoping
here
is clear: the foo in (1+ foo) is outside the scope of the
declaration.
If the SPECIAL declaration is to apply to the init forms, LET can be a
macro that turns into two lambdas:
(let ((foo (1+ foo))) (declare (special foo)) foo)
=> ((lambda ()
(declare (special foo))
((lambda (foo) foo) (declare (special foo)) (1+ foo))))
Some implementations do work this way.
!
Received: from USC-ECL.ARPA by SU-AI.ARPA with TCP; 10 Mar 86 20:19:59
PST
Date: Mon, 10 Mar 86 19:01:24 PST
From: Jeff Barnett <jbarnett%NRTC@USC-ECL.ARPA>
To: common-lisp@SU-AI.ARPA
Subject: Re Scope and declarations
Via: Nrtc; 10 Mar 86 20:04:19
Sorry I wasn't specific enough in my last query. Therefore, I'll start
from scratch. The point that bothers me is the one made on page 155 of
CLtL. As I understand things,
(setq x 5)
(defun foo (x)
(declare (unspecial x))
(let((x (1+ x)))
(declare (special x))
x)
(print (foo 0)) outputs 6, not 1. The declare in the let form
prevades the preset expression so that the expression (1+ x) assumes the
current global binding of x outside outside the let. I can understand
that this will often be the right thing and require less writing. I
also understand that if I want to grab the lexical x that I could change
the let to start
(let((x (let()(declare (unspecial x)) (1+ x)))) which I suppose works.
(Does it?) However, if the let is produced by a macro, there is no way
to achieve this effect unless the macro can enumerate the scope of the
expression that it uses for the preset. Since the preset may be passed
into the macro, I don't think it can recover in any graceful way unless
you think that
(let((g exp))
(let((x g))
(declare (special x)) etc)) where g is a gensym, is graceful.
Another problem with declares prevading presets is that the following
are not equivelent:
(let((v1 e1) (v2 e2)) (declare (something-about v1 v2)) body...)
((lambda(v1 v2) (declare (something-about v1 v2)) body...) e1 e2)
Further, I think the proposed standard is incompatible with virtually
all other LISP implementations. I don't think that this is a good idea
for CL. Any comments and clarifications as to all of this would be
appreciated.
Jeff
!
Received: from SCRC-STONY-BROOK.ARPA by SU-AI.ARPA with TCP; 5 May 85
16:33:05 PDT
Received: from RIO-DE-JANEIRO.SCRC.Symbolics.COM by
SCRC-STONY-BROOK.ARPA via CHAOS with CHAOS-MAIL id 230444; Sun 5-May-85
19:31:32-EDT
Date: Sun, 5 May 85 19:30 EDT
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: mysterious declarations off in left field
To: Fahlman@CMU-CS-C.ARPA
cc: Common-Lisp@SU-AI.ARPA
In-Reply-To: <FAHLMAN.12108630198.BABYL@CMU-CS-C.ARPA>
Message-ID: <850505193039.6.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
Date: Sun, 5 May 1985 14:12 EDT
From: "Scott E. Fahlman" <Fahlman@CMU-CS-C.ARPA>
Don't packages offer an alternative way of scoping declarations?
Sure, but packages normally function at a very large grain size.
Sometimes you want to add something to a package without having to
scan
the whole package definition to ensure that some fool has not
declared X
to be a quadruple-float.
Or SPECIAL! I've already had problems in Macsyma source code with
closures that didn't "close" because someone decided STRING should be a
special variable. I guess you can imagine how that would be a pretty
high-probability variable name and a poor choice of special name ...
Consider too that names like LIST, STRING, etc. are not likely to be
private -- nearly everyone is going to inherit them from GLOBAL -- so
the first time anyone in any "package" declares one of them to be
special, it screws everyone else who tries to do compilations in that
environment.
If I bind a lexical X, that's my X and I'm not interested in anyone
else's views about what type X's in general should be.
Indeed.
Actually, I wonder if we shouldn't have said that type proclamations
should pertain only to special variables. eg,
(PROCLAIM '(TYPE FLOAT TOLERANCE))
might have only applied to special occurrences of TOLERANCE. This would
mean that people using variables lexically in other modules would be far
less likely to find irrelevant declarations affecting them...
In cases where people wanted to make assertions about lexical variables,
they should perhaps have to scope such declarations lexically.
Although obviously such a change is somewhat incompatible, we might
consider it (or something like it) for the next round of revisions. (An
alternate approach which would achieve the same end would be to
introduce a new declaration operator which had the property of applying
only to special
occurrences so that people could choose which style they wanted.)
Of course this doesn't solve the problem I alluded to earlier of having
people declare things special behind my back...
!
Received: from MIT-ML by SU-AI with TCP/SMTP; 20 Dec 83 12:52:05 PST
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Tue 20-Dec-83
15:53:04-EST
Date: Tue, 20 Dec 83 15:50 EST
From: "David A. Moon" <Moon%SCRC-TENEX@MIT-MC.ARPA>
Subject: Declarations
To: Common-Lisp@SU-AI.ARPA
I have an alternate proposal for declarations. It is mainly intended as
an easier-to-understand way of explaining things that gives the same
semantics, but it also resolves the inconsistencies in the manual (Mary
Poppins and Excelsior editions) in a way that is probably inconsistent
with the intent of the manual, but is more consistent with the Laser
edition and with the practice in previous lisps such as Maclisp and Lisp
Machine Lisp. I realize it is rather late for this kind of thing, but
given that the manual is inconsistent with itself and that some people
were surprised by the change from last year's version of the language,
maybe we can reconsider. In any case this way of explaining things seems
to be easier to understand.
The basic problem is the SPECIAL declaration, which falls into both
categories of declarations: it both concerns the binding of variables
and is pervasive. This is not well explained in the manual and seems to
be a great source of confusion. I propose to flush the idea that
SPECIAL declarations are pervasive. Read on before judging.
There are two disjoint classes of declaration: those that are attached
to a particular variable binding, and those that are not. Note that I
am not discussing proclamations here; they have their own scoping rules
which are different from the rules for declarations.
The scoping rule for the first kind of declaration is that it applies to
precisely the text that is in the lexical scope of the variable binding
with which it is associated. Such declarations are shadowed by a
variable binding for the same name inside their scope. Since the
lexical scoping rules are very well and precisely defined, we already
understand everything about this kind of declaration.
The scoping rule for the second kind of declaration is that it is
pervasive. The declaration is attached to a lambda-expression or to a
form (one of the special forms listed on page 125). The declaration
applies to all text inside that expression or form; there are no special
cases such as init-forms of LET or DO. Such declarations are shadowed
by a conflicting declaration inside their scope.
Possible names for the two kinds of declaration are "lexical" and
"pervasive" or "variable" and "non-variable."
None of this is new. What about SPECIAL declarations? I propose that
SPECIAL declarations be put entirely into the first category, in the
following way:
When a declaration, (SPECIAL X), is attached to a form (or
lambda-expression) it creates a -lexical- binding of the name X in that
form. Unlike all other bindings, this binding does not associate a
value with the name X. Instead, it associates a "special" marker with
the name. Any text that is in the lexical scope of this binding, and
uses the variable X, refers to the dynamic binding of X, because it sees
the "special" marker. The scope of a SPECIAL declaration is precisely
defined by the scope of this binding. Note how close this definition is
to the way that some interpreters actually work internally.
In addition to creating this lexical binding, a (SPECIAL X) declaration
also changes the meaning of a binding, if there is one, of the variable
X in the form to which the declaration is attached; it causes that
binding to be a dynamic binding rather than a lexical binding. This
applies only to the form to which the declaration is directly attached,
not to any subforms of it. (This is not new.)
The declaration-allowing forms FLET, LABELS, LOCALLY, and MACROLET do
not normally create bindings of variable names (only function names), so
we have a slight exception, permitting SPECIAL declarations inside them
to create such bindings.
We now understand completely how the SPECIAL declaration works in LET.
Three examples:
(defun foo (x)
(let ((x x))
(declare (special x))
(bar x))) Reading from left to right, there are five occurrences of
x. The declaration causes the second and fifth to refer to a dynamic
variable, while the first and third refer to a lexical variable. (The
fourth occurrence is the one in the declaration itself). The third
occurrence of x does not refer to the dynamic variable, because it is
not in the scope of the lexical binding of the name x created by the
special declaration, because of the way LET defines scoping in its
subforms.
(defun foo ()
(declare (special x))
(bar x)) The declaration causes the second occurrence of x to refer,
freely, to a dynamic variable, because this x is inside the lexical
scope of a binding of the name x attached to the defun.
(defun foo ()
(let ((x (quux)))
(mumble x)
(locally
(declare (special x))
(bar x)))) Here the first and second occurrences of x refer to a
lexical variable, while the fourth refers to a dynamic variable. The
binding of the name x in the LOCALLY shadows the binding of the name x
in the LET.
There remains the issue of how sequential binding forms such as LET* and
DEFUN should work. (DEFUN uses sequential binding with respect to
initial value forms for &optional, &key, and &aux variables). When a
SPECIAL declaration creates a lexical binding of a name in such a form,
at what position in the sequence of bindings should it be inserted?
This makes a difference because it affects whether the scope of the
declaration includes or excludes the initial value forms. Clearly if
the form includes a (dynamic) binding of the name being declared, then
the (lexical) binding created by the declaration should be inserted at
that point. Otherwise we can either insert the declaration's binding at
the beginning of the sequence of bindings, giving it the largest
possible scope, or at the end, giving it the smallest possible scope. I
suggest putting it at the beginning, because that is what people seem to
expect with DEFUN (see the example at the bottom of page 126.) Two
examples:
(defun foo (x)
(let* ((x (bar x))
(y (quu x)))
(declare (special x))
...)) The first and third occurrences of x refer to a lexical
variable, while the second and fourth refer to a dynamic variable. (bar
x) is outside the scope of the special declaration while (quu x) is
inside its scope.
(defun foo (x)
(let* ((w (bar x))
(y (quu x)))
(declare (special x))
...)) The first occurrence of x refers to a lexical variable, while
the second and third refer, freely, to a dynamic variable. Both (bar x)
and (quu x) are inside the scope of the special declaration. If let had
been used instead of let*, neither of them would be inside the scope of
the declaration.
For explanatory purposes, the above two examples could be written on
paper as
(defun foo (x)
(let* ((x (bar x))
(x @I[special])
(y (quu x)))
(declare (special x))
...))
(defun foo (x)
(let* ((x @I[special])
(w (bar x))
(y (quu x)))
(declare (special x))
...))