
Beyond Exception Handling: Conditions and Restarts - DanielRibeiro
http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
======
awj
This is the one feature I wish I could steal from Common Lisp in almost every
language I work with. It would be much easier to put in than almost any other
big lisp feature, and damn would it make a lot of things easier.

~~~
sedachv
This is something you can do in most languages if all the code that needs
restarts follows a convention/protocol. Red Daly implemented CL condition
handling for JavaScript for the Parenscript CL-to-JS compiler:
[https://github.com/gonzojive/paren-
psos/commit/6578ad223515d...](https://github.com/gonzojive/paren-
psos/commit/6578ad223515dc2c1ddf49346f4baf7c3bee37c4)

The compiled CL code knows about the convention and follows it, but other
JavaScript code doesn't and isn't affected by it.

~~~
awj
Yeah, that's why I talk about stealing it at the language level. Although it's
possible to use this based on conventions, the real power comes from being
able to use it to cover weird conditions while gluing various libraries
together. If your language already has a relatively similar tool (i.e.
"traditional" exceptions) there's basically no chance that anything you pick
up will support conditions.

That said, it's a wonderful model to know about/follow if you come into the
rare case that makes reimplementing it where you can useful.

~~~
sedachv
This is true for Common Lisp libraries as well - if they don't offer restarts
and just throw exceptions, it looks like it does in any other language.
Developing a good protocol for signalling and handling errors takes work.

------
someone13
Is there any other language that implements this? I'll freely admit that I'm
no expert on Lisp, so I've tried digging through the code, and I sorta get
what the concept is, but I don't really _understand_ it. Any other languages
have the same idea?

~~~
briantrice
Dylan does, and my language Slate (<http://www.slatelanguage.org>) does, as
well as its related younger siblings, Atomo (<http://atomo-lang.org>) and
Atomy (<http://atomy-lang.org>). And all of these implement them in the
context of an object model, rather than carefully avoiding CLOS dependencies
as in CL.

~~~
bakkdoor
I just added conditions & restarts today to Fancy (<http://fancy-lang.org/>).
It's currently in a branch but it works =).

~~~
briantrice
Thanks for doing that. More implementations means there's a wider spectrum of
places for developers to learn these tools and maybe even improve on them.

------
IgorPartola
Does this basically mean that CL provides a mechanism that's lower level than
what is otherwise equivalent to exceptions/warnings, and that this in turn
enables things like restarts? Is this analogous to the relationship between
higher level control structures such as if/for/while/break/continue vs the
lower-level goto? Lastly, can some of these features not be implemented with
exceptions?:

    
    
      def parse_log_file(f):
          result = []
          for line in f.readlines(): # Fails for large files
            parsed_line = None
            retries = 0
            while retries < 5:
                try:
                    result.append(parse_log_entry(line))
                    break
                except MalformedLogEntry:
                    line = fix(line)
                    retries += 1
          return result

~~~
Kototama
Your code is not equivalent. There is a separation of concerns that is
possible with conditions/restarts that is not possible with exceptions.

The calling code can choose the appropriate restarts base on information that
the callee code does not - and should not - have access to.

~~~
IgorPartola
> The calling code can choose the appropriate restarts base on information
> that the callee code does not - and should not - have access to.

In the common case, is that not equivalent to the caller catching specific
errors by wrapping the callee in a try/except? Could you elaborate?

~~~
Kototama
But this is assuming the caller has enough information to solve the problem,
which is not always the case (the callee could have information on the
structure of the disk that are not relevant to the caller for instance).

Conditions/restarts make a separation of concerns, particularly when the
caller knows which of the restart is the more appropriate, if the callee has
not enough information/context to choose, and if the callee has more
information on how to solve the problem.

I guess the separation can be summarized by: difference between knowing WHAT
and HOW to do something. A useful abstraction I guess.

~~~
IgorPartola
I see. So this would be somewhat like saying

    
    
      except MalformedLogEntry, ex:
          line = fix(line, ex)
    

and having _ex_ encode the information that _fix()_ needs to do its job?

If that's the case, then I can see the value in having the ability to pass
such information around baked into the language. The code I have is growing
more and more ugly, and the only way to simplify it is to introduce some kind
of a coding convention that is not common to Python.

~~~
Kototama
How would you do, in your case, if the parse_log_file function does not know
the best strategy if a log file is corrupted? Maybe this information is known
only by the caller.

I don't know how to solve that in a language without restarts. The information
of what to do could well be asked to the final user (with a dialog box) once
an error is catched, the callee would then restart _at the point where the
execution was interrupted_ applying the chosen strategy.

EDIT: rereading your Python code, I guess you're right and have the closest
equivalent.

~~~
IgorPartola
Ah. So the point is that the state of execution of parse_log_entry and
everything up the stack from it is frozen, and then an out-of-band exception
handler figures out what to do, fixes the condition that caused the error, and
resumes from the exact spot where the error was first detected, restarting
just the most low-level code block? Man, CL is pretty sweet.

This, by no coincidence I'm sure, reminds me a lot of how signals are handled
in UNIX/POSIX. I guess you could simulate this very crudely with those by
sending yourself a SIGUSR[1|2] :).

