[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
DECLARE SPECIAL Considered Confusing
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))
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
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
What do people think? It would appear that some implementations already
work this way.