Introducing try..catch #3
Description
If we find we really need new syntax to flag that people have thought about the consequences of multi-exceptions, we could switch the existing try..except
syntax to try..catch
. It seems most other languages use the latter keyword anyway.
Syntax
The syntax would just replace except
with catch
, leaving everything else the same.
We have the option however of disallowing catch:
(i.e. with no exception, the catch-all block) -- forcing people (and automatic translators) to write catch BaseException:
.
Note that catch
would have to be a soft keyword (supported by the new PEG parser, see PEP 617), since there are plenty of other uses of catch
in existing code that we don't want to break.
Transition
The transition plan would be that try..exept
will eventually be removed from the language. There would be three stages:
try..catch
andtry..except
can both be used.try..except
works but gives a deprecation warning.try..except
stops working.
Possibly stage 2 can be split and try..except
inside async
functions can be deprecated sooner than in other contexts.
During stages 1 and 2, each try
statement must use either catch
or except
-- you cannot have both catch
and except
blocks in the same statement. (But you can have them in the same file.)
Semantics
When the raised exception is not a multi-exception the semantics of try..catch
is the same as for try..except
.
When the raised exception is a multi-error the semantics change.
Basically when a multi-error contains different exception types it is possible that more than one catch
block runs. E.g.
try:
raise MultiError([ValueError(), ZeroDivisionError(), RuntimeError()]) # or whatever
catch ValueError:
print("VE")
catch RuntimeError:
print("RE")
would print "VE" and "RE" and then raise (bubble up) RuntimeError()
(or MultiError([RuntimeError()]
).
If there's an else
block it only gets run if no exceptions were raised in the first place.
If there's a finally
block it gets run after all catch
blocks (if any) have run, before bubbling up the unhandled exceptions (if any).
The order in which the exceptions in the multi-error are handled is just the order in which the MultiError
object regurgitates them.
Multiple exceptions of the same type
This is an open issue.
What if the try block raises MultiError([ValueError("A"), ValueError("B")])
? We could define different semantics.
Note that there would also be a question about two different exception classes that derive from the same base class, where the catch
class specifies that base (or ultimately catch BaseException
). So we cannot rely on MultiError
to split exceptions based on class before we start matching exceptions to catch blocks.
TO BE CONTINUED IN A LATER COMMENT (I deleted some meta-comments related to this.)