The proposed omnibus Exceptions RFC uses the following three
rules to guide it while unwinding through the clauses of a
try statement.

Rule 1: Uncaught Exceptions Propagate

    At the end of the try statement, you are going to continue
    unwinding up another level if *anything* threw, *unless* a
    catch clause was invoked after the throw, and said clause did
    not throw, and no clauses invoked after said clause (such as
    finally clauses) threw either (unless they too were caught
    without throwing).

    Since exception handling is to be used for error handling,
    we want failure to fail unless we explicity and successfully
    handle it.

Rule 2: Finally is Always Attempted

    Whether or not anything under a try throws, once the try has
    started, its finally clauses are attempted.

    Finally clauses are typically used to restore invariants or
    otherwise "clean up" no-matter what failed (including nothing),
    and then let unwinding up another level (propagation) depend on
    whether or not something did in fact fail.

Rule 3: Catches Happen Until Handled

    Catch clauses are only invoked if a previous clause threw,
    and if since then no subsequent catch clause was invoked and
    completed without throwing.

Is rule 3 justified?  Consider the following cases:

    try { } finally { }

        The finally is invoked whether or not the try threw.

        Unwinding happens if either try or finally threw.

        Otherwise, no throw occurred.  No catching is involved.

    try { } catch { }

        The catch is invoked only if the try threw.

        Unwinding happens if try threw and catch threw.

        Otherwise no throw occurred, or it was completely caught.

    try { } catch { } finally { }

        The catch is invoked only if the try threw.

        The finally is invoked whether or not try or catch threw.

        Unwinding happens if try and catch threw, or finally threw.

        Otherwise no throw occurred, or it was completely caught.

    try { } finally { } catch { }

        The finally is invoked whether or not the try threw.

        The catch is invoked if try threw or finally threw.

        Unwinding happens if try or finally throws, and catch throws.

        Otherwise no throw occurred, or it was completely caught.

    try { } except { } => catch { }

        The catch is invoked if try threw and the except clause
        did not throw and it returned a true result.

        Unwinding happens if try threw and (1) except threw or
        returned false, (2) except returned true and catch threw.

        Otherwise no throw occurred, or it was completely caught.

The cases shown above are straightforward.  Now consider this case.

    try { } except { } => catch { }
            except { } => catch { }
            catch  { }

The potential problem is that if the first catch throws, then
the second except will be testing against the $@ from the catch,
not the $@ from the try.  This can be avoided by using the
following synatx from the proposed omnibus Exceptions RFC:

    try { }

    except { $@->any(... $_[0] ...) } => catch { }
    except { $@->any(... $_[0] ...) } => catch { }

    catch { }

Is this a problem?

Yours, &c, Tony Olekshy

Reply via email to