Design of Exceptions and EHM in Cforall:


Exception Instances:
Currently, exceptions are integers (like errno).

They are planned to be the new "tagged structures", which allows them to
exist in a simple hierarchy which shared functionality throughout. However
the tagged structures are not yet implemented so that will wait.

A single built in exception is at the top of the hierarchy and all other
exceptions are its children. When you match against an exception, you match
for an exception and its children, so the top of the hierarchy is used as a
catch-all option.

The shared functionality across exceptions has not been finalized, but will
probably include things like human readable descriptions and default handlers.


Throwing:
There are currently two kinds of throws, "throw" for termination and
"throwResume" for resumption. Both keywords can be used to create a throw
statement. The kind of throw decides what handlers may catch the exception
and weither control flow can return to the throw site.

Syntax
"throw" exception ";"
"throwResume" exception ";"

Non-local throws are allowed for resumption only. A target is an object with
a stack, with which it may propagate and handle the exception.

Syntax
"throwResume" exception "_At" target ";"

Termination throws unwind the stack until a handler is reached, control moves
onwards from the end of the handler. Resumption throws do not unwind, if a
handler is found and control will return to the throw after the exception is
handled.


Catching:
The catch and handle of an exception is preformed with a try statement, which
also can have finally clauses to exceute on exit from the scope.

Syntax
"try"
	try-block
( ("catch" | "catchResume")
  "(" exception_type [identifier] [";" conditional_expression] ")"
	catch-block
)*
("finally"
	finally-block
)?

Either at least 1 handler clause or the finally clasue must be given on each
try block. Each handler clause handles 1 of the two types of throws. Each
handler also specifies a type of exception it handles, and will handle all
children exceptions as well. In addition, a conditional expression which, if
included, must be true for the handler to catch the exception.

The two types of handlers may be intermixed. Multiple handlers catching the
same type may also be used, to allow for fallbacks on false conditionals.


Implementation Overview:

The implementation has two main parts. The first is just a collection of the
support definitions we need, the data types and functions used within the
exception handling code. Second is a translation from Cforall code to C code
that uses those definitions to throw, catch and handle exceptions.

Termination handlers call a specially annotated function, passing it inner
functions that act as the varius sub-blocks. Termination throws use the
unwind library that checks the underlying code for those annotations. Each
time one is found some magic is used to check for a matching handler, if one
is found control goes to the special function which excecutes the handler and
returns.

Resumption handlers maintain a linked list of stack allocated nodes that have
the handler functions attached. Throwing a resumption exception traverses this
list, and calls each handler, the handlers handle the exception if they can
and return if they did or not.

Finally clauses just use stack cleanup to force a nested function, which has
the code from the finally clause, to execute when we leave that section.


Alternative Error Handling: Return Unions

Return unions (Maybe and Result), are types that can encode a success or
other result in a single value. Maybe stores a value or nothing, Result stores
a value or an error.

For errors that are usually handled quite close to where they occur, these
can replace exceptions.

They tend to be faster and require similar or less amounts of code to handle.
However they can slow down the normal path with some extra conditionals and
can mix the normal and exceptional control flow path. If handling the error
is simple, and happens relatively frequently, this might be prefered but in
other cases it just hurts speed and readability.

In short, these errors seem to be more effective when errors are likely and
immediate. High failure operations, especially ones with failures that can
be handled locally, might be better off using these instead of exceptions.

Also the return unions could use exceptions as well. Getting the improper
side of a return union might throw an exception. Or we can provide helpers
for results withe exceptions as in:
		forall(otype T, otype E | exception(E))
		T get_or_throw (Result(T, E) * this) {
			if (has_value(this)) {
				return get_value(this);
			} else {
				throw get_error(this);
			}
		}
