6 ms·
Exception handlers are continuations.
by useerup 5y ago
Exception handlers are continuations.
- formerly_proven 5y agoI don't think they are, unless you are talking about the few implementations of resumable exceptions. The most obvious counter-example I can think of is C++, where the stack from where the exception was thrown is unwound to the handler, i.e. it's destroyed (doubly so if the exception handler puts anything on the stack). That's also why you can't get a stacktrace from an exception in C++ unless you specifically arranged for the thrower to include that information in the exception object.
- toolslive 5y agoIn continuation passing style, a compiler technique, exceptions show up quite naturally as a second continuation. The whole thing is called "Double barrelled continuation passing style".
- miloignis 5y agoI believe exceptions are equivalent to a limited form of continuations called escape continuations where control flow can only go upwards (which is the stack unwinding). Note that this is also true of break and continue, actually, both of which can be implemented with either exceptions or escape continuations.
- PaulDavisThe1st 5y agoYou can get the stack trace by breaking in "throw". Maybe you meant something else.
- formerly_proven 5y agoBreakpoints on throw are triggered before unwinding (you are effectively setting a breakpoint on the function called to unwind). You simply cannot create a stack trace from within a C++ exception handler because that state is gone. Hence my argument that exceptions are not a continuation, there is nothing to continue.
- PaulDavisThe1st 5y agoAll true. But also a bit of a diversion, because the information you wanted "from within" the exception handler is available at the throw site. Ergo, if you're trying to get it from within the handler, you're just trying to get it from the wrong place.
- simiones 5y agoEven resumable exceptions are/can be much more bounded than continuations. Exceptions always respect the scope structure of the code (even though they can jump between scope levels), whereas continuations can break this arbitrarily. In particular, in Common Lisp, restarts are only valid in the dynamic environment where they were created by restart-bind. In contrast, call/cc captures this dynamic environment and makes it available later. You can't store restarts and invoke them later the way you can with call/cc.
- simiones 5y agoI'm guessing you're trying to equate try{ foo() }catch(Exception e){ bar(e) } void foo() { throw new exception(); } with (bar (call/cc foo)) (defun foo (cont) (cont (make-exception)) However, this ignores most details of the problem. In fact, (re-entrant) continuations and exceptions can't be mixed in the same language: Common Lisp has not adopted `call/cc` for one because it's impossible or at least much harder to implement `unwind-protect` (`finally`) in the presence of `call/cc` [0]. The major difference is that continuations allow you to do this: (defparam *global*) (defparam *shadow-list* (list)) (defun foo (cont) (setf *global* cont)) (with-open-file (f "~/file.log") (loop for line = (read-line stream nil 'eof) until (eq line 'eof) collect (cons line (call/cc foo))) (*global* *shadow-list*) (*global* *shadow-list*) ;; what is the state of the file here? what if there was an exception reading from the file? [0] https://groups.google.com/g/comp.lang.lisp/c/1Ggl_BUi3Yg/m/VFTIDaJqRK8J?pli=1 https://groups.google.com/g/comp.lang.lisp/c/1Ggl_BUi3Yg/m/V...
- kragen 5y agoNaw, it's not impossible; you just use dynamic-wind. But to me this has a bit of the spirit of "Now, you have two problems..."
- simiones 5y agoWell, dynamic-wind itself does not do what unwind-protect does. You have to manually "save/resume" the dynamic environment with the after/before clauses of dynamic-wind. To be fair, it's probably relatively easy to use dynamic-wind to raise some runtime error when trying to resume the continuation after the original context "ended".
- kragen 5y agoIt doesn't, no, but yes, that was my thought: write a version of with-open-file implemented in terms of dynamic-wind that raises a runtime error if you try to reenter. Better hope people are using call/cc for exception handling and not threading though... Pitman's comments on this are in http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuations-original.html http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuat..., Sitaram's response is at http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.79.3107 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.79.3..., and Pitman's final response is at http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuations-update-2003.html http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuat....
- cout 5y agoI have seen exceptions implemented with setjmp/longjmp, and I have seen continuations implemented with setjmp/longjmp/memcpy. So they are definitely related, but equivalent? Or are you saying something else?