On Fri, 25 Sep 2020 at 15:57, Paul Moore <p.f.mo...@gmail.com> wrote: > > On Fri, 25 Sep 2020 at 14:15, Chris Angelico <ros...@gmail.com> wrote: > > > Why? Do you really think you can enumerate EVERY possible way that > > something might fail? > > Rust does a surprisingly good job of that, actually. But the point is > that Python is not Rust, and the infrastructure Rust uses to allow it > to manage code safety is baked into the language core at a very > fundamental level. > > Enumerating the exceptions that a piece of code can raise is > impractical and unhelpful in Python. But that may not be immediately > obvious to someone coming from a different language. That's why it's > important to understand Python properly before proposing new features > that work in other languages. (I don't think that's what the OP is > doing here, to be clear, but the discussion is drifting in that > direction, with Rust's Result type having been mentioned). > > **In Python**, writing code from the perspective of "what can I handle > at this point" is the right approach. Deferring unexpected exceptions > to your caller is the default behaviour, and results in a clean, > natural style *for Python*. The proposal here is basically in direct > contradiction to that style.
I do agree but maybe that suggests a different role for annotated exceptions in Python. Rather than attempting to enumerate all possible exceptions annotations could be used to document in a statically analysable way what the "expected" exceptions are. A type checker could use those to check whether a caller is handling the *expected* exceptions rather than to verify that the list of *all* exceptions possibly raised is exhaustive. Consider an example: def inverse(M: Matrix) -> Matrix: raises(NotInvertibleError) if determinant(M) == 0: raise NotInvertibleError rows, cols = M.shape for i in range(rows): for j in range(cols): ... Here the function is expected to raise NotInvertibleError for some inputs. It is also possible that the subsequent code could raise an exception e.g. AttributeError, TypeError etc and it's not necessarily possible to enumerate or exhaustively rule out what those possibilities might be. If we wanted to annotate this with raises(NotInvertibleError) then it would be very hard or perhaps entirely impossible for a type checker to verify that no other exception can be raised. Or maybe even the type checker could easily come up with a large list of possibilities that you would never want to annotate your code with. Maybe that's not what the purpose of the annotation is though. What the type checker can do is check whether a caller of this function handles NotInvertibleError after seeing the *explicit* type hint. A function that calls inverse without catching the exception can also be considered as raises(NotInvertibleError). You might want to enforce in your codebase that the caller should catch and suppress the expected exception or should itself have a compatible raises annotation indicating that it can also be expected to raise the same exception e.g. either of these is fine: def some_calc(M: Matrix): raises(NotInvertibleError) A = inverse(M) ... def some_calc(M: Matrix): try: A = inverse(M) except NotInvertibleError # do something else ... Perhaps rather than requiring all exceptions to be annotated everywhere you could allow the raises type hints to propagate implicitly and only verify them where there is another explicit type hint: def some_calc(M): # no hint but checker infers this raises NotInvertibleError A = inverse(M) def other_func(M): raises(ZeroError) # checker gives an error for this # because the raises should include NotInvertibleError B = some_calc(M) You could then have an explicit hint for the type checker to say that a function is not expected to raise any exceptions maybe like this: def main(args): raises(None) ... The intent of this would be that the type checker could then follow the chain of all functions called by main to verify that any exceptions that were expected to raise had been handled somewhere. This wouldn't verify all of the exceptions that could possibly be raised by any line of code. It could verify that for those exceptions that have been explicitly annotated. Oscar _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/L2YK75C7XSFWOJLM6ROAI3ZVAY2WE5GZ/ Code of Conduct: http://python.org/psf/codeofconduct/