Thank you very much!
my $bill =
try ack() orelse
try thpp() orelse
This certainly does what I asked for, and it's short enough (even if we
need to add a few brackets).
Yes, the basic problem with the proposal is that it catches all
exceptions willy nilly and uses them all for control flow whether
that is appropriate or not. I have some sympathy with the proposal,
however, because I'm currently using exceptions for just that
purpose in the STD grammar. But it's suffering from the same
difficulty, and I have to be careful to rethrow if the exception
I trapped wasn't the one I expected.
It might also be useful to have a try variant that only catches
exceptions intended as benign failure to match. Or maybe try should
have a way of indicating the severity of exception it wishes to
trap by default. This could be a keyword variant, or an adverb,
or a pragma. I'm thinking the pragma is most likely to distribute
syntactic relief nicely over a lexical scope. In any case it would
only set the default CATCH handler which could still be overridden in
any particular try block.
I believe that ---from a usability point of view--- it's very important to:
* classify exceptions by "severity" or other characteristics,
* provide named adverbs/pragmas to modify default CATCH handlers,
* make them configurable by "outer scopes".
Without such conventions (e.g. with just catching individually named
exception classes), the programmer of a function often cannot reasonably
know what exceptions he should catch and how he should handle them.
There are two reasons for this and here are two examples.
The first reason is: The programmer isn't supposed to know all
exceptions that can be thrown by sub-routines. Otherwise, you can't
add a new feature to a library function (and introduce a new exception
with it) without breaking the error handling of all code that
uses this library function.
Also, some general functions (e.g. macro/template-expanders)
can include an unspecified set of extension modules and hence can't
know all the exceptions that will be needed for these extensions.
This problem can be solved by grouping exceptions into meaningful
groups and catching groups, not individual exceptions.
For example, there are quite a lot of situations where a function
cannot produce an expected result (e.g. read_file($non_existing_file)).
Such exceptions just say that you can't rely on any results that depend
on the output of this function. These exceptions should be catched by //.
A different group of exceptions is where the user wants to terminate
a computation (e.g. CTRL-C//HUP).
The second problem goes into the opposite direction: Even if you
have well-defined exception groups, you cannot always know how
they should be handled.
Take, for example, a macro processor (like LaTeX) used for
typesetting a book and an exception that indicates that some required
information (e.g. a reference) is not available. Should this exception
be catched and a placeholder be included --- or should this exception
be fatal for this job?
The answer is: during proofreading, this should produce a warning
and a readable result. In production scripts (process and print
a few million books), this needs to be fatal.
Of course, the programmer of the macro processor cannot decide
whether the processor is used in proofreading or in production code.
This decision must be made "upstream", by callers of the processor.
The same problem is: should attempts to access protected files
be fatal security alerts or just missing values?
This problem can be resolved by having configurable CATCH handlers
that are defined by the callers of a function and only referred to by name.
So, we may have three separate programmers that are responsible for
The programmer of a low-level function or extension module throws
exceptions and classifies them into meaningful severity groups.
The programmer of the top-level function defines the severity of
particular exception groups for this specific application by defining named
The middle-ware programmer doesn't have the responsibilities
of the low-level or top-level programmers, and can't make
decisions for them. He just uses the appropriate named CATCH
handler to do "the right thing".
And if we really go so far, we can have standard names for two
CATCH handlers: "CATCH://" and "CATCH:orelse". The operators
can catch the corresponding exceptions --- leaving the specification
of which exceptions to handle to the programmer.