Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
What's a condition system and why do you want one? (axisofeval.blogspot.com)
35 points by uros643 on April 28, 2011 | hide | past | favorite | 9 comments


One thing that hasn't been pointed out is how the Common Lisp condition system provides a sane alternative to the Unix signal(7) brain-damage. To quote the Hyperspec:

  If the condition is not handled, signal returns nil.
http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec...


I think they really serve different purposes. signal(7) is a software interrupt mechanism. Its purpose is to allow your program to respond to external events without having to poll for them. (In particular, it provides a way for your program to exit gracefully when it's stuck in an infinite loop and the user kills it, and it provides a way for your program to handle page faults in userland — too bad the parameters needed to handle page faults aren't standardized across Unices.)

Like other interrupt mechanisms, it also gets used for error exits in languages that don't have them inherently, but it's a pretty bad way to do that.


If you take a look at Kent Pitman's paper, linked from the post, (http://www.nhplace.com/kent/Papers/Condition-Handling-2001.h...), particularly the section 'Unifying "Signals" and "Exceptions"', he points out that signal(7) is actually doing two orthogonal things - process interrupt, and signal raising.

He also points out how the signal(7) and Lisp conditions came out of Multics. If you consider it that way, it becomes clear that the Unix decision to overload signal(7) with two different functions is why it is such a poor interface and major source of pain.


For Ruby, check out http://cond.rubyforge.org/


Interesting... I was just coming to the conclusion that such a thing would be handy, as so many things use exceptions as a way of, essentially, returning multiple values. It's rampant - add an item to a set where it already exists, and it throws. Which costs a lot compared to returning false due to the stack-unwinding, but is more flexible. Typically though, the stack-unwinding is entirely unnecessary, the class / message is more than enough to determine the source of the problem. And such a thing would turn try/catch blocks into a loosely-coupled implicit delegate system, which strikes me as fantastically useful.


> Which costs a lot compared to returning false due to the stack-unwinding

The relative costs are dependent on the language implementation. longjmp() in C is only roughly as expensive as a normal function return, but of course setjmp() costs an extra two or three function calls' worth. And in many interpreters, exceptions are basically free.

(Except on MacOS, where setjmp() and longjmp() are an order of magnitude slower because they involve system calls.)

I had a discussion with a mainframer a couple of years back about what kinds of things people did in assembly that aren't reflected in C. One interesting technique he mentioned was incrementing the return address in case of error returns, so the function actually had two different possible points to return to; the calling code would look something like this (x86 version):

        CALL SOMEROUTINE
        JMP 1f
        JMP ERROR
    1   ; continue with normal processing
In case of error, the routine bumped its return address by the size of a jump instruction before returning to the JMP ERROR instruction.

Such a pattern would be awfully disconcerting if you weren't used to it, of course.

Multiple return values were, of course, another thing he mentioned. Any caller-saved register can double as an additional return value.


Would this be pretty easy to implement in a language with first class functions (albeit with more boilerplate) just by keeping a list of functions to be invoked before raising an exception?


You can get most of the way there using such an approach, but it'll never feel quite "right" unless your language gives you lots of syntactic sugar to play with.

You've also got to be careful about how your handler stack interacts with threads and/or coroutines.

For an example that I think same up pretty well, but certainly not as elegant as the system built into lisp, check out my "withrestart" python module: https://github.com/rfk/withrestart


Yes, but you'd also need to fake dynamic scoping. Check out Red Daly's implementation of the CL condition system for JavaScript/Parenscript, it's only about 200 lines of code:

https://github.com/gonzojive/paren-psos/commit/6578ad223515d...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: