From: Chip Salzenberg <[EMAIL PROTECTED]> Date: Sat, 24 Jun 2006 21:56:32 -0700
On Sat, Jun 24, 2006 at 11:18:41PM -0400, Bob Rogers wrote: > . . . I even intend to use continations to implement THROW and CATCH; I > just won't be able to expose them to users via standard Lisp constructs. > So, yes, I could install the equivalent of an UNDO block around the Lisp > code that does whatever Parrot maintenance is required on the Parrot > exception object (which, it now occurs to me, may need to be distinct > from the Lisp condition object). But would I really need to do anything > here? If an exception is caught by Lisp, why would Parrot even need to > know? S04 seems to require a great deal of bookkeeping for unhandled > exceptions, but would that necessarily impact Lisp handlers? It's just a little hack, no big deal. Imagine this scenario: 1. Parrot has exceptions 2. Parrot requires handlers to mark exceptions handled with a "caught" [now "handled"] opcode 3. Parrot has dynamic-wind Given: (handler-case (signal condition) (printer-on-fire () YOUR_FORM_HERE)) Your CL compiler would replace YOUR_FORM_HERE with the equivalent of this, written in pidgin Scheme . . . Impressive. This is close to what I had in mind for the general case when I said "I could install the equivalent of an UNDO block around the Lisp code ..." above. It looks like you're beginning to think like a Lisp implementor. (Are you scared yet?) But your implementation is really for this use of HANDLER-BIND: (handler-bind ((printer-on-fire #'(lambda (cond) YOUR_FORM_HERE))) (signal condition)) (Please bear with me here, I'm trying to draw parallels between CL and Perl 6 error semantics.) Typically, HANDLER-CASE is implemented in terms of HANDLER-BIND, and creates a handler for PRINTER-ON-FIRE errors that does a nonlocal transfer-of-control to the dynamic context of the HANDLER-CASE. (This is easier, in that code emitted by the compiler knows that it's doing a nonlocal exit and can emit a C<handled> op directly.) The YOUR_FORM_HERE body [1] therefore runs in the original HANDLER-BIND contenxt, not the error-signalling context. However, I notice that S04 doesn't explicitly specify the dynamic environment for anything evaluated in a CATCH block. (Indeed, it seems to use the terms "handler" and "CATCH block" interchangeably.) Would the CATCH block still be in scope as a handler while it was executing? This seems problematic, so I am hoping it's an oversight. If so, then that would make my life easier. A key aspect of both HANDLER-CASE and HANDLER-BIND is that none of the handlers they establish are in scope when those handlers are invoked. That way, if a badly-written handler should be prone to (re)igniting printers, you don't get looping. But if you really do want CATCH blocks to be in effect when run, then I have two ideas for PIR-level APIs for changing this default: 1. Implement "catch-out-of-own-scope" by default and let CATCH blocks re-establish themselves when they execute, e.g. by doing a C<push_eh_self> in the preamble; or 2. Store the list of active handlers in a global variable so that PIR handler code can rebind them dynamically. I suspect that the lexical nature of the 'handled' flag may not match the interpreter-wide-dynamic nature of the signal stack, leading to incorrect results with nested signals. But with that caveat, I think this would work. You might also get odd results if the context was re-entered and re-exited while some other error was being signalled. For instance, what would happen the second time your dynamic-wind cleanup block is run? (This couldn't happen in vanilla CL, but might in Parrot if the handler called something else that took a continuation.) However, this ought to be fixable by having the C<handled> instruction mention the exception that it wants to mark as caught. -- Bob [1] The spec calls them "error clauses"; see http://www.lispworks.com/documentation/HyperSpec/Body/m_hand_1.htm#handler-case