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

Issue: EXIT-EXTENT



I have several problems with the proposal for this issue.

  Date: 31 Oct 88 12:25 PST
  From: masinter.pa@Xerox.COM

    ...

  The ambiguity only arised because of unwind-protect.

Agreed.

    ...

  Given a block (block frob ...) which contains a (return-from frob ...) in it,
  we normally think of (return-from frob ...) as a "instantaneous" operation.

I don't agree with this at all.  I have never thought of the invocation of an
exit to be an "instantaneous" operation, due to the possible presence of
unwind-protects.  This part of my mental model for Lisp execution dates to well
before I ever got involved in implementation, so I don't think it is biased by
any particular implementation.  If I had encountered the behavior Symbolics
Genera exhibits without having seen the proposal, I would have submitted a bug
report. 

    ...

  If the extent is over only when the block is exited, then the following cases
  would *not* be an error: 

    < several examples >

This is the interpretation which I believe is correct.  The extent of an object
with dynamic extent is the extent of the form which created it.  Code which is
executed "within" that form is within the extent of the object(s).  This
applies to all dynamic objects, such as special variable bindings, not just
exits.  Actually, I think the intent of the implementation note on p.142 is
fairly clear and supports this interpretation.  The supposedly ambiguous
use of "frame" should be read as something like "form which establishes a
dynamic extent".  It might be clearer if the last sentence were changed to
read something like:

"On the second pass the stack is actually unwound.  Each form which establishes
a dynamic extent is undone in reverse order of creation until the matching
catch is reached.  The meaning of undoing a form depends on the type of form.
For unwind-protect, it means executing the cleanup forms.  For catch it means
removing the catch tag.  For dynamic bindings it means undoing the binding,
restoring the previous saved value. {This is not an exhaustive listing of the
possibilities.}"

One of the alternatives mentioned in the proposal would be to "duck the issue
by outlawing all nonlocal exits from UNWIND-PROTECT cleanup forms".  As noted,
this alternative might have a substantial cost to some users.  However, it
seems to me that the proposal just about collapses to this alternative, since
there is in general no way to determine the target of the nonlocal exit, so the
cleanup forms usually cannot safely do any nonlocal exits without extra code to
in some way record the target.  In fact, in many implementations, due to the
presence of things like ABORT interrupts and such, it is probably almost
impossible to be certain of the target for a nonlocal exit.

I find it disturbing that the current dynamic environment of a cleanup form
depends on how the unwind-protect was exited.  This problem is even more
apparent if you extend the proposal to also apply to special variable bindings
in a manner similar to the way catch is specified in the proposal.  (Of course,
doing so would violate the implementation note on p.142).  I don't think you
can talk about the dynamic extent of exits in the way the proposal does without
also talking about the dynamic extent of other forms under the same situations.
And I think if you extend the proposal to other forms, the results begin to
look more and more strange.  For example,

    (block nil
      (let ((x 5))
        (declare (special x))
        (unwind-protect (return)
          (print x))))				;is this an error?

    (block nil
      (let ((x 5))
        (declare (special x))
        (unwind-protect
            (if (test) (return))
          (print x))))				;is this an error?

In the first example, if the dynamic extent of special variables is similar to
catchers, then under the proposal it is an error.  Similarly, in the second
example it is an error if (test) returns true, but might be ok if (test)
returns false.  It demonstrates an example of the problem I mentioned earlier,
of determining what things are dynamically available in the unwind-protect
cleanup forms.

And now for a slightly less contrived example which would probably be in error
under the proposal.  This is boiled down to mostly the essentials to keep from
cluttering it up, but I think it should be apparent that this is not a totally
unreasonable code fragment.

    (block nil
      (handler-case
          (unwind-protect (return)
            (error "foo"))             ;probably an error, under the proposal
        (error ()
          (print "foo"))))

If the ERROR handler has the same scope and extent a CATCH in the same place
would have (and that seems reasonable, though I'm not certain that the
condition system specifically requires that interpretation), then the handler
will be apparent to the call to ERROR, but will no longer be a valid target
(its extent was exited by the RETURN in the UNWIND-PROTECT body).

I understand the desire expressed in the proposal to avoid changing the
language in a way which invalidates certain implementation techniques, and
agree wholeheartedly with this desire.  However, I believe that the proposal
is in fact a change, rather than a clarification (as the proposal claims), and
that it is a change for the worse.

kab
-------