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

Issue: DECLARATION-SCOPE



You are asking a broader set of questions that Horning apparently didn't 
want to address in his original cleanup proposal.  There are a plethora 
of issues related to this -- the whole semantics of declarations in Common 
Lisp seems to be in disarray now.

I think these broader issues must be raised, and that is one reason why 
what started out as a very small clarification has grown into a much 
larger controversy.  Perhaps it was premature to think we could take the 
dragon by the tail and not feel his hot breath too.  I would actually
like to see a *coordinated* set of cleanup issues on declarations.
"Coordinated", because it often doesn't make sense to talk about these
issues in isolation; witness the extremely close link of this scoping
proposal with the FLET-DECLARATIONS:ALLOW proposal.

If this proposal -- DECLARATION-SCOPE:LIKE-VARIABLE is to be seriously
considered in isolation, the I would at least like to suggest an alteration
as outlined below.  First, a very brief overview of the proposal:

Hornig's purpose stated in the original message of 
"Tue, 5 Jan 88 08:21 EST" was:

    . . .  The issue is
    whether the scope of some or all of the declarations includes code
    appearing in the non-body part of the special form containing the
    declaration.
    . . . 
    `Normal' declarations are made to control a particular binding of a
    variable and should be scoped the same way as that binding.  This is as
    true of `normal' declarations which were pervasive under the old rules
    as it is of those that were not.

So the original DECLARATION-SCOPE proposal would seem to be addressing
the specific kinds of problem illustrated by this example:

    (setf (symbol-value 'x) 0)
    (trace car)

    (defun foo (x y)
      (let ((x (car y))
	    (car (+ 4 x)))
	(declare (special x) (inline car +))
        (list car (car x))))

A reasonable test, after compiling [and hypothetically assuming that a call
to CAR that isn't declared "inline" will go out-of-line] works like:

    (foo 4 '((hello))) 	==>   {fn: CAR, arglist: ( ((hello)) )}	;trace output
			      (8 hello)

namely, that unlike in some implementations, the special declaration
does not apply to the form "(+ 4 x)", and further, the inline declaration
applies to "(car x)" but not to "(car y)".

But still a lot of issues are left open.  [One of them, for example, is 
how to say that the inline declaration of "car" above doesn't apply to 
the binding of the variable "car" established in the special form in 
which the declaration occurs 'normally'.  It seems obvious to a reader 
with intuition; it's not so obvious from reading all the legalese and
generalizations of a formal prescription.]

I call attention again to Hornig's guiding principle:

    `Normal' declarations are made to control a particular binding of a
    variable and should be scoped the same way as that binding. 

I think it would be a great simplification that declares in a binding
special form (like, LET, PROG, LABELS, etc) should either "control
a particular binding" and thus by definition have the scope of that 
binding [and nothing more], or be scoped as follows.  For those 
declarations that in a binding special form that don't correlate with 
any of the bindings being established -- like the inline declaration 
for "+" in the example above -- their scope should be the same as if 
there had been a "variable" in the binding list for it to "control".

That is, rather than

      (let ((z (+ 4 x)))
	(declare (special z) (inline +))
        (+ z 5))

being equivalent to

      (locally (declare (inline +))
        (let ((z (+ 4 x)))
	  (declare (special z))
          (+ z 5)))

I think it would be more consistent for it to be equivalent to:

      (let ((z (+ 4 x)))
	(declare (special z))
	(locally (declare (inline +))
          (+ z 5)))

I could submit a proposal called DECLARATION-SCOPE:FULLY-LEXICAL to specify
this.  But as I said before, I think there are a whole plethora of issues
that ought to be considered together, so some attention needs to be paid
to all the related issues.

This FULLY-LEXICAL approach would help certify one of your feelings; you
posed the example

    (DEFUN FOO-1 (X)
      (DECLARE (INLINE FOO-1))
      (+ X 1))

    (DEFUN BAR-1 (X) (FOO-1 X))

and suggeted that the inline declaration should not apply to the "reference"
to FOO-1 in function BAR-1.  Easily handled by the "lexical" approach.

However, I would even question the appropriateness a form like

    (DEFUN FOO-3 (X)
      (DECLARE (FUNCTION FOO-3 (FIXNUM) FIXNUM))
      (+ X 1))

The kind of binding being in this special form is a LAMBDA binding -- 
a "variable" binding, not a "function" binding -- so the ftype declaration 
on FOO-3 certainly doesn't apply to X.  Hence it ought not to act like a 
global proclaim.  Indeed, PROCLAIM exists precisely to cover the case of 
setting a global function cell; and this isn't the same kind of binding 
that occurs in, say, FLET, or LABELS.  To achieve the effect you are
supposing, you might have to say:

    (locally (declare (function foo-3 (fixnum) fixnum))
      (defun foo-3 (x)
        (+ x 1)))

or possibly

    (defun foo-3 (X)
      (flet ((foo-3 (x) 
               (+ x 1)))
       (declare (function foo-3 (fixnum) fixnum))
      (foo-3 x)))



-- JonL --