On Tue, Jul 30, 2013 at 5:23 AM, David Jeske <[email protected]> wrote:

> Further, there is something which feels incompatible about current stack
> unroll propagation and handling generic errors with catch-all try blocks.
> Downstream code expects to throw exceptions through intermediate callers,
> so how do those intermediate callers handle binary success/fail in the next
> immediate level?
>
I'm not sure what you mean by the "next immediate level" here. I do agree
that there are designs in which exceptions are propagated across
intermediate stack frames by design, and that this practice can backfire.
It's one of the places where I think tools would be helpful.

There is a particular idiom which exposes the kind of thing that [I think]
concerns you very clearly. It occurs when a caller passes a first-class
procedure down into a call stack, and the first-class procedure performs a
non-local exit using the exception mechanism by sending a "proprietary"
exception up the call stack. This can work out very badly if the contract
and convention for resource release and state modification in the
intermediate callers isn't *very* carefully specified and *very *carefully
adhered to.


In my personal experience, the problem that tends to get people in trouble
isn't so much the resource release aspect of exception handling as the need
to be careful about mutating retained state in the presence of possible
exceptions. Most people don't really know how to go about writing
transaction-safe programs. What they end up doing instead is making
optimistic mutations and trying to back them out in finally blocks. This
leads to something a bit worse than the code duplication pattern that you
mentioned: it creates what might be termed *reverse* code duplication,
which is harder and more error prone.

And I think it can be argued fairly that this problem is *exacerbated* by
the fact that pass-through error checking in an exception system is
invisible. An unintended, but useful, purpose of the errno checks around
every procedure call is that it forces the programmer to maintain awareness
of all the points where an error might be introduced. It is far too easy in
an exception-based system to perform a mutation and then make a potentially
exceptional procedure call without realizing that you have done so. This is
*especially* true when you have automatic inlining.

One of the mistakes (in my opinion) in C# is that the default checking of
arithmetic can be changed by a compiler switch. People can make strong
arguments for doing it one way or the other by default. The problem in C#
is that the contract is unknown and not part of the interface type, so
programmers must behave as if basic arithmetic can generate exceptions.
Under this assumption in particular, it's almost *impossible* to write
imperative code that unwinds mutations successfully. The burden of recovery
is just too high.

I'm not sure that the error code approach really changes this, except by
making subtle issues more apparent. I *do* think that tooling could go a
long way to bridge the gap.
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to