[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: DECLARE SPECIAL Considered Confusing

    Date: 11 Jul 86 18:43 PDT
    From: Pavel.pa@Xerox.COM
    In this message I will give a complete description of my proposal for
    declaration scoping.  I won't attempt to argue for it on the basis of
    ``obviousness'' or clarity, though, because I think that there are
    people who find each of the two ways of scoping special declarations
    confusing.  Rather, I like this way of doing things because it satisfies
    an important (to me) consistency criterion: the scope of \any/
    declaration coincides with a particular lexical identifier scope.

I don't think you mean 'any' here; I think you mean 'any declaration
that concerns the bindings of variables' (cf. pg. 154).  You cannot
mean 'any' since in the example below
(let ((x 1))
  (declare (inline foo))
  (foo x))
the declaration does not 'coincide with a particular lexical
identifier scope.' A more extreme example is
(let (...)
 (declare (optimize ...))
in which the declaration does not refer to ANY named entity.

If we consider declarations that only concern the bindings of
variables, we see that CLtL already agrees with your consistency
criterion: "[Declarations] that concern variable bindings apply only
to the bindings made by the form at the head of whose body they
appear." (pg. 154) Thus by definition, the scope of the decl. is the
scope of the binding.

Thus in the following example of valid CL code
(let ((x (oddp x)))
  (declare (type (member t nil) x))
The declaration has no effect on the reference of x in
the init form.

Unfortunately, TYPE and IGNORE are the only decl specs that only
concern bindings.  SPECIAL concerns bindings also, but it
also pervasively affects references (this is what you want changed).
And FTYPE and INLINE simply confuse me.

First of all, FTYPE is not explicitly stated to be a pervasive decl
spec, I believe this is an omission.  Secondly, there is this
confusing sentence at the end of their descriptions:

"Note that the rules of lexical scoping are observed; if one of the
functions mentioned has a lexically apparent local definition (as made
by FLET or LABELS), then the declaration applies to that local
definition and not to the global definition."

This makes it sound like FTYPE and INLINE are like SPECIAL: they
concern bindings AND affect references (but not pervasively?).

For example,
(FLET ((zap (...)...(zap...)...))
  (declare (inline zap))

Is the call to zap in the local definition of zap affected by the
declaration?  My reading of CLtL and commonsense make me answer no.
The call to zap is not a call to the local def. of zap, and according
to my reading of the sentence quoted above, the decl. only affects
references within the scope of the innermost binding of the name zap.
But this interpretation depends upon not interpreting 'pervasively' as
stated in CLtL. Is my interpretation correct?

If so, it seems to me that FLET and INLINE already work in an intuitive
manner.  Consider the following example:

(FLET ((zap () (zoop)))
  (declare (inline zoop))

According to my reading of CLtL, the call to zoop IS affected by the
declaration.  And this makes sense to me.  I could not tell from
Pavel's proposal whether or not this would be true in his proposal.

I propose the following change to CLtL (which pretty much agrees with
both CLtL and Pavel):

For all decl specs that concern named entities (and this includes all CLtL
decl specs except OPTIMIZE (the DECLARATION decl spec doesn't really

If the name mentioned in the decl spec of a declaration that appears
at the beginning of a form in whose 'head' the name is bound, then the
declaration affects that binding and all references within the
binding's scope.

Otherwise, if the name mentioned in the decl spec of a declaration
that appears at the beginning of a form is not the name of a binding
established by that form (this is just another way of stating what was
stated in the antecedent of the above sentence), then the declaration
does not affect any binding, but it affects all references in the
entire form (from the open parenthesis to the close).

In addition, the distinction between 'pervasive' and non-pervasive
declarations should be flushed.  It is a bogus distinction.

Some examples should help clarify this:

(let ((y x))
  (declare (type list x))
Both references to x are affected.  This would be a new (upward
compatible) feature (and a useful one I think).  Note:  Currently,
TYPE is said to 'affect' only bindings.  This is bogus.  It also
affects all references to the binding.  This can be seen in many
compilers when one references the binding incorrectly, e.g.,
(let ((x 1))
  (declare (type integer x))
  (car x))

(let ((x x))
  (declare (type list x))
Only the second reference to x is affected (since the first reference
is not within the scope of the binding named by x.  The binding of x
is also affected (i.e., type checking may be done at
binding/assignment time).  This example is also valid for the SPECIAL
dec spec.

(let ((x 1))
  (declare (type t x))
  (let ()
    (declare (type cons x))
    (setf x (cons 1 2))
The 'reference' to x in the SETF form is affected by the second
declaration only (as is the other reference).

(let ()
  (declare (ignore x))
The reference to x is affected (The compiler should issue a warning
that an ignored variable was referenced.).  This kind of declaration
might be useful in code generated by a macro to cause a check that
user written code in the body does not reference certain 'reserved'

(FLET ((zap (...)...(zap...)...(zoop...)...))
  (declare (function zap (...)...)
           (function zoop (...)...))
The call to zap is not affected, but the call to zoop is.

(LAMBDA (&optional (x x) (y (zap x)))
  (declare (type list x)
           (function zap...))
Only the second ref. of x is affected.  The call to zap if affected by
the FUNCTION decl spec.

Here comes the only new, incompatible (with some implementations:-)
(let ((x 'local))
  (let ((x 'special)
        (y x))
    (declare (special x))
The ref. to x is not affected by the declaration (x still refers
to the lexical binding.).  This is different from current CLtL

(let ((x 1))
  (let ((y x))
    (declare (special x))
BOTH refs. to x ARE affected by the declaration.  This is actually
consistent with current CLtL semantics.

Finally, decl specs that do not concern named entities (the only one
in CL is OPTIMIZE), always affect all subforms within the form in
which the decl spec is declared.

I believe this proposal is complete, consistent, and simple to apply.


-- Nick