Cond: Resolve errors without unwinding the stack


#1

Hello –

Here is a portion of the readme for this new project. For those
unfamiliar with condition systems, I recommend watching a few minutes of
Seibel in the video mentioned below.

= Cond

== Description

Resolve errors without unwinding the stack.

== Synopsis

require ‘cond’
include Cond

def divide(x, y)
restartable do
restart :return_this_instead do |value|
return value
end
raise ZeroDivisionError if y == 0
x/y
end
end

handling do
handle ZeroDivisionError do
invoke_restart :return_this_instead, 42
end
puts divide(10, 2) # => 5
puts divide(18, 3) # => 6
puts divide(4, 0) # => 42
puts divide(7, 0) # => 42
end

== Install

% gem install cond
or
% ruby install.rb [–uninstall]

== Overview

Cond allows errors to be handled near the place where they occur,
before the stack unwinds. It offers several advantages over
exceptions while peacefully coexisting with the standard exception
behavior.

The system is divided into two parts: restarts and handlers. When
+raise+ is called and there is a matching handler for the error, the
normal mechanism of unwinding the stack is suspended while the handler
is called instead. At this time, the handler may invoke one of the
available restarts.

A handler may find a way to negate the problem and, by invoking a
restart, allow execution to continue from a place proximal to where
+raise+ was called. Or a handler may choose to allow the exception to
propagate in the usual unwinding fashion, as if the handler was never
called.

Cond is 100% compatible with the built-in exception-handling system.
We may imagine that Ruby had this handler/restart functionality from
the very beginning, but everyone had forgotten to write restarts. And
since no restarts were available, no handlers were written.

== Background

Cond is stolen from the Common Lisp condition system.

Peter Seibel discusses the advantages of handlers and restarts in the
following video. I have fast-forwarded to the most relevant part,
though the whole talk is worthwhile.

http://video.google.com/videoplay?docid=448441135356213813#46m07s

The example he shows is taken from his book on Lisp,

http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html

See readmes/seibel_pcl.rb for a Ruby translation.

== Synopsis 2.0

x, y = 7, 0

handling do
handle ZeroDivisionError do |exception|
invoke_restart :return_this_instead, 42
end

result = restartable do
  restart :return_this_instead do |value|
    leave value
  end

  raise ZeroDivisionError if y == 0
  x/y
end

puts result  # => 42

end

== Technical Notes

Cond has been tested on MRI 1.8.6, 1.8.7, 1.9, and the latest jruby.

Each thread keeps its own list of handlers, restarts, and other data.
All operations are fully thread-safe.

It is not required to include Cond. The includable methods
of +Cond+ are module_functions and are thus callable via e.g.
Cond.handling.

+Cond+ nests private modules and classes inside Cond::CondPrivate in
order to improve the hygiene of include Cond and encourage
its use.

Except for the redefinition +raise+, Cond does not silently modify any
of the standard classes

== Links

==

I am open to suggestions on anything from syntax to terminology. For
example I experimented with a “body” block so that the the main code
could appear before the handlers and restarts. And I once used “on” to
replace both “handle” and “restart”, e.g., “on ZeroDivisionError do
…”.

James M. Lawrence