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

UNWIND-PROTECT-CLEANUP-NON-LOCAL-EXIT



    Date: Fri, 1 May 1987  23:26 EDT
    From: "Scott E. Fahlman" <Fahlman@C.CS.CMU.EDU>
    In-reply-to: Msg of 23 Apr 1987 02:07-EDT
	         from David A. Moon <Moon at STONY-BROOK.SCRC.Symbolics.COM>

	...
	Note that signalling an error must
	avoid the following pitfall once an error-handling facility is added to
	Common Lisp:

	  (loop
	    (ignore-errors
	      (unwind-protect (loop)
		(error))))

	The illegal-nested-throw error must not be caught by ignore-errors or
	nothing will have been solved.

Personally, I consider the meaning of this to be well-formed. It'd be
sad for a programmer to get into this, but I think that in this case
the user has pretty clearly asked to have a loop that cannot be exited
and deserves to have that request carried out. 

Consider how ridiculous it would have looked on Star Trek when they
needed to divert the computer's attention and said "Computer, compute to
the last digit the value of pi".  If I recall, Spock makes a remark like
"As you know, the value of pi is a transcendental number without
resolution. ... The computer will work on this problem to the exclusion
of all else ...". Imagine how frustrated he'd have been if the computer
had refused to execute the command because it didn't seem like he really
meant what he said.

Well, ok, so this isn't the most likely scenario. But the truth is,
as Prof. Bill Martin said once in a linguistics class I took from him --
We create syntax in a language not to allow us to say the things that
are obvious, but so that we can say things that are not obvious. If we
didn't need to say things that were not obvious, we'd just jumble all
the words together and assume people would figure out some uniquely 
determined, obviously useful interpretation. In fact, we make careful
rules to allow us to say bizarre things not so we can say bizarre things
all the time, but so that if there comes a time to say such things, we
won't be at a loss for words.

By the way, I did once write a CL program that wanted the semantics that
Moon claims are implausible. In Common Lisp, there was no portable way to
make a Lisp have a Macsyma toplevel (ie, where the vendor's abort character
would return me to Macsyma and not to Lisp). So I wrote something which did
effectively:
 (DEFUN MACSYMA-TOPLEVEL ()
   (PROG ()
     LOOP (UNWIND-PROTECT (REALLY-MACSYMA-TOPLEVEL)
			  (GO LOOP))))
so that people who'd invoked Macsyma toplevel couldn't get back to toplevel
lisp. So while it might be rare, it's not unthinkable that someone could really
write this and mean what they said...

As such, I don't rate this desire to let the user intervene at the same
level of importance that Moon does. However, since I do find it an
interesting issue, I'm willing to entertain the issue for discussion
for now without prejudice to its ultimate importance.

    I guess we need a class of errors that don't get ignored, despite the
    user's instructions.  There are probably some other members of this
    class.  Some asynchronous things that have nothing to do with the code
    inside the IGNORE-ERRORS form might qualify: system almost out of
    memory, memory error, and stuff like that.

If we did make this illegal, I'm curious exactly what Moon would want to
have happen here. The most plausible scenario I can come up with that fits
in this hypothetical framework is the following (which is essentially like
what Scott is suggesting) ...

 THROW could notice that it was going to THROW to a point inside
 a THROW which was already active. At this point, it could signal
 a SERIOUS-CONDITION (some type which was not a subtype of ERROR),
 so that IGNORE-ERRORS did not catch the condition, but that did
 have a default handler that would force entry into the debugger.
 This would allow an opportunity for user-intervention.

 The debugger could offer options which should include:

   * Going ahead with the inner THROW (and discarding the outer
     THROW attempt).

   * Exiting from this UNWIND-PROTECT cleanup body and continuing
     the ongoing THROW.

   * Blowing away the process without running its UNWIND-PROTECT
     cleanups.

 This would allow for user intervention without precluding what
 I believe to be the clean semantics (choice C). I'm suspicious
 of any choice which doesn't even allow the user to get style-C
 semantics if that's what he wants.

Dave, is this the sort of thing you're proposing? If not, could
you please sketch what you are suggesting for contrast?

By the way, I ran across the following piece of mail the other day
while looking around for something else. I just thought you'd be
interested to know that this problem is as old as UNWIND-PROTECT
itself; the message is from only a few days after UNWIND-PROTECT
was first installed in Maclisp and although the bug is not like
the one we're discussing, the test scenario is a lot similar to
the code sketch Moon did above...

-----Forwarded Message Follows-----
Date: 29 April 1980 16:09-EDT
 From: Jon L White <JONL at MIT-MC>
To: KMP at MIT-MC, RWK at MIT-MC
cc: BUG-LISP at MIT-MC
Subject: UNWIND-PROTECT

On the 15th of Feb, KMP sent out a bug notice about UNWIND-PROTECT
losing, for which I made the diagnosis that ERRSET was not saving
and restoring the UNREAL flag. The test case is
 (DEFUN KMP-LOSES () (ERRSET (UNWIND-PROTECT NIL (OPEN '((DSK BOO) BAR BZ)))))
Well, I found a way to fix ERRSET without taking more pdl locations,
and the assembled code (already initialized) is on LISP;BBLISP 995QIO.
...