Re: [Python-ideas] Make return inside a finally a SyntaxError
I agree that having finally subsume returns and exceptions in the try block will at first be surprising to people, and that it can lead to easy-to-create but difficult-to-find bugs. But I think the current behavior is definitely for the best: - It's dead simple. The finally clause is always done last, and is always responsible for the return of the function *no matter what* may have happened in the try clause. - If finally were to automatically propagate any exception from the try clause, how would you turn that off when you needed/wanted to? You'd soon wind up wanting another keyword, perhaps seriouslyfinally, that was guaranteed to be run at the very end. If finally propagated exceptions, what should it do if there's an exception raised in the finally block? It begins to get complicated. The primitive blanket solution is better, IMO. - Besides, if you do want a finally clause to propagate an exception from its try clause, that's simple as you can just store the exception somewhere in an except clause and then let the finally detect it and re-raise it, if appropriate. By keeping finally's semantics simple and resisting the temptation to make it more sophisticated (e.g., propagating exceptions or return values) you wind up with a better tool for the programmer who does know what they're doing. The more sophisticated behavior can easily be added as you need it on a case-by-case basis. The added functionality shouldn't be provided unconditionally by the language because you then can't disable it. I.e., I prefer the control I get from the current semantics of finally. Terry
2009/7/18 Terry Jones <terry@jon.es>
I agree that having finally subsume returns and exceptions in the try block will at first be surprising to people, and that it can lead to easy-to-create but difficult-to-find bugs.
But I think the current behavior is definitely for the best:
- It's dead simple. The finally clause is always done last, and is always responsible for the return of the function *no matter what* may have happened in the try clause.
Finally is normally dead simple but the explanation usually includes what it does with exceptions: Finally is *always* run last. Exceptions that occur in the try block are re-raised once the finally has completed. Exceptions inside the finally block will be re-raised The bit that has to be *added* in Python (and usually isn't added because it isn't at all obvious) is: Exceptions are not reraised if the finally returns or breaks.
- If finally were to automatically propagate any exception from the try clause, how would you turn that off when you needed/wanted to? You'd soon wind up wanting another keyword, perhaps seriouslyfinally, that was guaranteed to be run at the very end.
No, you'd use the already present and obvious except where you have the *choice* of re-raising or ignoring the exception.
If finally propagated exceptions,
It does.
what should it do if there's an exception raised in the finally block?
It re-raises it on exit (except for two special cases - return and break). Try it.
It begins to get complicated.
No, it gets simpler - no special cases for the exception handling of finally in the presence of a return. Michael
The primitive blanket solution is better, IMO.
- Besides, if you do want a finally clause to propagate an exception from its try clause, that's simple as you can just store the exception somewhere in an except clause and then let the finally detect it and re-raise it, if appropriate.
By keeping finally's semantics simple and resisting the temptation to make it more sophisticated (e.g., propagating exceptions or return values) you wind up with a better tool for the programmer who does know what they're doing. The more sophisticated behavior can easily be added as you need it on a case-by-case basis. The added functionality shouldn't be provided unconditionally by the language because you then can't disable it. I.e., I prefer the control I get from the current semantics of finally.
Terry _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
2009/7/18 Michael Foord <fuzzyman@gmail.com>:
Finally is normally dead simple but the explanation usually includes what it does with exceptions:
Finally is *always* run last. Exceptions that occur in the try block are re-raised once the finally has completed. Exceptions inside the finally block will be re-raised
The bit that has to be *added* in Python (and usually isn't added because it isn't at all obvious) is:
Exceptions are not reraised if the finally returns or breaks.
While I'll concede that it's a bit subtle, the finally doesn't "complete" if you return or break - those two statements cause premature exit. As such, it's quite right that the exception isn't re-raised in those cases, as the finally clause never "completed". Subtle, yes. Inconsistent, no. Paul.
Paul Moore wrote:
While I'll concede that it's a bit subtle, the finally doesn't "complete" if you return or break - those two statements cause premature exit. As such, it's quite right that the exception isn't re-raised in those cases, as the finally clause never "completed".
Subtle, yes. Inconsistent, no.
This is the reason the current semantics make sense to me as well: return, break and raise all mean that the finally block doesn't actually finish, so the implicit "re-raise" at the end of the finally block is never executed. If anything was going to be made more consistent, I would suggest it would be to allow continue in a finally statement with similar semantics to break. I suspect there may be implementation factors that would make that difficult though. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Michael Foord wrote:
Exceptions that occur in the try block are re-raised once the finally has completed.
That's correct if you understand "completed" to mean "by falling off the end". A doc enhancement is perhaps in order to make that clearer. -- Greg
Dnia 18-07-2009 o 14:07:06 Terry Jones <terry@jon.es> napisał(a):
I agree that having finally subsume returns and exceptions in the try block will at first be surprising to people, and that it can lead to easy-to-create but difficult-to-find bugs.
IMHO it is enough to treat it as a bug.
But I think the current behavior is definitely for the best: [snip] - If finally were to automatically propagate any exception from the try clause, how would you turn that off when you needed/wanted to? You'd soon wind up wanting another keyword, perhaps seriouslyfinally, that was guaranteed to be run at the very end.
No, simply: try: try: ... finally: ... except Foo: ...
If finally propagated exceptions, what should it do if there's an exception raised in the finally block? It begins to get complicated. The primitive blanket solution is better, IMO.
But normally finally propagates exceptions. The problem is that 'return' breakes that rule. A rule that is both logicall and intuitive.
- Besides, if you do want a finally clause to propagate an exception from its try clause, that's simple as you can just store the exception somewhere in an except clause and then let the finally detect it and re-raise it, if appropriate.
Do you think about: try: exc = None .... except BaseException as exc: pass finally if exc: raise exc else: return foobar ...? Easy, this example is a joke. The workaround is: not to use return in finally. Never. (After all if you need catch an exception, you should use except).
By keeping finally's semantics simple and resisting the temptation to make it more sophisticated (e.g., propagating exceptions or return values) you wind up with a better tool for the programmer who does know what they're doing.
IMHO rather the current behaviour is sophisticated, or rather surprising and weird. Regards, zuo
participants (6)
-
Greg Ewing
-
Jan Kaliszewski
-
Michael Foord
-
Nick Coghlan
-
Paul Moore
-
Terry Jones