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.