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 and try..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.)
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..exceptsyntax totry..catch. It seems most other languages use the latter keyword anyway.Syntax
The syntax would just replace
exceptwithcatch, 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 writecatch BaseException:.Note that
catchwould have to be a soft keyword (supported by the new PEG parser, see PEP 617), since there are plenty of other uses ofcatchin existing code that we don't want to break.Transition
The transition plan would be that
try..exeptwill eventually be removed from the language. There would be three stages:try..catchandtry..exceptcan both be used.try..exceptworks but gives a deprecation warning.try..exceptstops working.Possibly stage 2 can be split and
try..exceptinsideasyncfunctions can be deprecated sooner than in other contexts.During stages 1 and 2, each
trystatement must use eithercatchorexcept-- you cannot have bothcatchandexceptblocks 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..catchis the same as fortry..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
catchblock runs. E.g.would print "VE" and "RE" and then raise (bubble up)
RuntimeError()(orMultiError([RuntimeError()]).If there's an
elseblock it only gets run if no exceptions were raised in the first place.If there's a
finallyblock it gets run after allcatchblocks (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
MultiErrorobject 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
catchclass specifies that base (or ultimatelycatch BaseException). So we cannot rely onMultiErrorto 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.)