Design of Exceptions and EHM in Cforall:

Currently this is a combination of ideas and big questions that still have to
be addressed. It also includes some other error handling options, how they
interact and compare to exceptions.


What is an Exception:

In other words what do we throw? What is matched against, how does it carry
data with it? A very important question that has not been answered.

Option 1: Strutures

Considering the current state of Cforall the most natural form of the
exception would likely be a struture, implementing a trait repersenting the
minimum features of an exception. This has many advantages, including arbitray
fields, some polymorphism and it matches exceptations of many current systems.

The main issue with this is matching, without OOP inheritance there is no
exception hierarchy. Meaning all handling has to happen on the exact exception
without the ease of grouping parents. There are several ways to attempt to
recover this.

The first is with conditional matching (a check after the type has been
matched) which allows for matching particular values of a known type. However
this does not dynamically expand and requires an extra step (as opposed to
mearly allowing one). I would not recomend this as the primary method.

Second is to try and use type casts/conversions to create an implicate
hierachy, so that a catch clause catches anything of the given type or
anything that converts to the given type.

Plan9 (from what I know of it) would be a powerful tool here. Even with it,
creating a hierarchy of types at runtime might be too expencive. Esecially
since they are less likely to be tree like at that point.

Option 2: Tags

The other option is to introduce a new construct into the language. A tag
repersents a type of exception, it is not a structure or variable (or even
a normal type). It may be usable in some of those contexts.

Tags can declare an existing tag as its parent. Tags can be caught by handlers
that catch their parents. (There is a single base_exception that all other
exceptions are children of eventually.) This allows for grouping of exceptions
that repersent similar errors.

Tags should also have some assotiated data, where and on what did the error
occur. Keeping with the otherness of exception tags and allowing them to be
expanded, using a parameter list. Each exception can have a list of paramters
given to it on a throw. Each tag would have a declared list of parameters
(which could be treated more like a set of fields as well). Child tags must
use their parent's list as a prefix to their own, so that the parameters can
be accessed when the child tag is matched against the parent.

Option N: ...

This list is not complete.


Seperating Termination and Resumption:

Differentating the types of exceptions based on exception would be hard with
exceptions as structures. It is possible with exceptions as tags by having
two base exceptions, one for each type of throw. However recompining them
to dual types would be harder.

Reguardless, using different keywords would also be useful for clarity, even
if it does not add functality. Using the C++ like keywords would be a good
base. Resumption exceptions could use a different set (ex. raise->handle) or
use resume as a qualifier on the existing statements.


Conditional Matching:

A possible useful feature, it allows for arbitrary checks on a catch block
instead of merely matching a type. However there are few use cases that
cannot be avoided with proper use of a type hierarchy, and this shrinks even
further with a good use of re-throws.

Also it assumes one sweep, that might also be a problem. But might also give
it an advantage over re-throws.


Alternatives: Implicate Handlers & Return Unions

Both act as a kind of local version of an exception. Implicate handlers act as
resumption exceptions and return unions like termination exceptions. By local
I mean they work well at one or two levels of calls, but do not cover N levels
as cleanly.

Implicate handles require a growing number of function pointers (which should
not be used very often) to be passed to functions, creating and additional
preformance cost. Return unions have to be checked and handled at every level,
which has some preformance cost, but also can significantly clutter code.
Proper tools can help with the latter.

However, they may work better at that local level as they do not require stack
walking or unwinding. In addition they are closer to regular control flow and
are easier to staticly check. So even if they can't replace exceptions
(directly) they may still be worth using together.

For instance, consider the Python iterator interface. It uses a single
function, __next__, to access the next value and to signal the end of the
sequence. If a value is returned, it is the next value, if the StopIteration
exception is thrown the sequence has finished.

However almost every use of an iterator will add a try-except block around the
call site (possibly through for or next) to catch and handle the exception
immediately, ignoring the advantages of more distant exception handling.

In this case it may be cleaner to use a Maybe for both cases (as in Rust)
which gives similar results without having to jump to the exception handler.
This will likely handle the error case more efficiently and the success case a
bit less so.

It also mixes the error and regular control flow, which can hurt readablity,
but very little if the handling is simple, for instance providing a default
value. Similarly, if the error (or alternate outcome) is common enough
encoding it in the function signature may be good commuication.

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 implicate handlers and return unions could use exceptions as well.
For instance, a useful default might handler might be to throw an exception,
seaching up the stack for a solution if one is not locally provided.

Or here is a possible helper for unpacking a Result value:
		forall(otype T, otype E | exception(E))
		T get_or_throw (Result(T, E) * this) {
			if (is_success(this)) {
				return get_success(this);
			} else {
				throw get_failure(this);
			}
		}
So they can feed off of each other.
