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
