Re: uncaught exceptions

Tim Peters (tim@ksr.com)
Fri, 17 Dec 93 21:50:19 EST

I'd like to second Steve's observation:

> ... I would propose that most of the language features in Python and
> most other OO programming languages are simply not strong enough to
> provide robust reusable modules BY THEMSELVES. That is: all of the
> language FEATURES all require a large matrix of USE CONVENTIONS that
> are usually not defined IN the languages itself. ( And I would guess
> that if you actually made all of those conventions LANGUAGE
> REQUIREMENTS, that you would end with something so constrained and
> pedantic that it would be rejected by most programmers.

W. Kahan (of IEEE-754 fame) once remarked that an "exceptional operation"
is one whose behavior a reasonable person could take exception to (pun
intended). People simply will not agree on what should and shouldn't be
"an error", and once exception-handling mechanisms are introduced to give
people a choice, they will far less agree on what to do with them.
Compared to VMS, Python appears much more to provide mechanism instead of
policy, and that's fine. But it does leave consistency up to the user.

Toward that end, I'm not sure the flexibility of Python's mechanism is
universally appreciated (Jaap did hint at it). For example, if you want
to build hierarchies of exceptions, the mechanism is already there.
E.g., if you want to call both overflow and divide-by-zero errors
"arithmetic errors", you can do

ArithmeticError = OverflowError, ZeroDivisionError

and then use the name ArithmeticError in an except statement. The
ArithmeticError tuple can itself be a component of higher-level
groupings, and on & on. The condition on Python's "except" can be any
expression (even a function call ...) evaluating to a tuple, and the
resulting tuple is "deep searched" for a match to the active exception.
I get the impression that most _believe_ the condition has to be a flat
display of bare exception names; if so, you're missing possibilities.

BTW, there appears to be a small bug here: the 'raise' statement requires
its first argument to evaluate to a string object, so I should not be
able to raise ArithmeticError as defined above (it's a tuple, not a
string). But:

>>> ArithmeticError = OverflowError, ZeroDivisionError
>>> ArithmeticError
('OverflowError', 'ZeroDivisionError')
>>> raise ArithmeticError # not a string, but error not caught
Stack backtrace (innermost last):
File "<stdin>", line 1
OverflowError
>>>

Or

>>> raise (('abc','def'),[3])
Stack backtrace (innermost last):
File "<stdin>", line 1
abc
>>>

Maybe we can use this in the obfuscated Python contest as a clever way to
suck the leftmost string out of a nested tuple <grin>.

Overall, I like Python's exception mechanisms very much, and don't mind
being asked to invent my own policy (although I confess I haven't yet
come up with a policy I'm completely happy with <sheepish grin>).

The one thing that still burns me is catching "unexpected" exceptions in
try blocks, and on third thought I'm not really happy with Jaap's "else:"
proposal: John is surely right that you _want_ to keep algorithmically-
related code together. Jaap's proposal eases the scattering somewhat, in
a stylized way, but only in the case where the code you don't want
handled is a proper suffix of the "try" block. What I would _really_
like is a piece of syntax to explicitly exempt arbitrary statements in
the "try" block from the overly-protective effect of the try block.
E.g.,

bumpedi = 0
try:
x = y*i
not try:
i = i + 1
bumpedi = 1
x = x*i
except OverflowError:
i = i - bumpedi
x = long(y)*i
i = i + 1
x = x * i

The idea being that the "not try" block would act, wrt exceptions, "as
if" it had been executed at the same level as the "bumpedi = 0" statement
(i.e., as if the smallest lexically enclosing try statement did not
exist; and it would be a translation-time error if a "not try" was not in
a "try" block).

Wow, that is ugly <0.9 grin>.

BTW, that's another example of an "expected exception": I do a lot of
number-crunching in Python, and for speed I often do computations with
short integers, knowing in advance that every now & again they'll
overflow. In the rare case that they do overflow, I simply redo the
computation using long arithmetic. Is this sick? Sure.

but-it's-effective<wink>-ly y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp