[Python-Dev] PEP 340: Deterministic Finalisation (new PEP draft, either a competitor or update to PEP 340)
Nick Coghlan
ncoghlan at gmail.com
Sun May 8 22:54:56 CEST 2005
Josiah Carlson wrote:
> The argument over whether blocks should loop, I believe has been had;
> they should. The various use cases involve multi-part transactions and
> such.
The number of good use cases for a looping block statement currently stands at
exactly 1 (auto_retry). Every other use case suggested (locking, opening,
suppressing, etc) involves factoring out try statement boiler plate that is far
easier to comprehend with a single pass user defined statement. A single pass
user defined statement allows all such code to be factored safely, even if the
main clause of the try statement uses break or continue statements.
The insanity of an inherently looping block statement is shown by the massive
semantic differences between the following two pieces of code under PEP 340:
block locking(the_lock):
for item in items:
if handle(item):
break
for item in items:
block locking(the_lock):
if handle(item):
break
With a non-looping user defined statement, you get the semantics you would
expect for the latter case (i.e. the for loop is still terminated after an item
is handled, whereas that won't happen under PEP 340)
For the one good use case for a user defined loop (auto_retry), I initially
suggested in my redraft that there be a way of denoting that a given for loop
gives the iterator the opportunity to intercept exceptions raised in the body of
the loop (like the PEP 340 block statement). You convinced me that was a bad
idea, and I switched to a simple iterator finalisation clause in version 1.2.
Even with that simplified approach though, *using* auto_retry is still very easy:
for attempt in auto_retry(3, IOError):
stmt attempt:
do_something()
It's a little trickier to write auto_retry itself, since you can't easily use a
generator anymore, but it still isn't that hard, and the separation of concerns
(between iteration, and the customised control flow in response to exceptions)
makes it very easy to grasp how it works.
>>>The closest thing to a generic solution I can come
>>>up with would be to allow for the labeling of for/while loops, and the
>>>allowing of "break/continue <label>", which continues to that loop
>>>(breaking all other loops currently nested within), or breaks that loop
>>>(as well as all other loops currently nested within).
Or, we simply have user defined statements which are not themselves loops, and
use them to create named blocks:
def block(name):
try:
yield
except TerminateBlock, ex:
if not ex.args or ex.args[0] != name
raise
stmt block('foo'):
while condition():
stmt block('goo'):
for ... in ...:
while other_case():
stmt block('hoo'):
if ...:
# Continue the inner while loop
continue
if ...:
# Exit the inner while loop
raise TerminateBlock, 'hoo'
if ...:
# Exit the for loop
raise TerminateBlock, 'goo'
# Exit the outer while loop
raise TerminateBlock, 'foo'
This has the benefit that an arbitrary block of code can be named, and a named
TerminateBlock used to exit it.
> That is a mechanism, but I like it even less than the one I offered.
> Every time that one wants ot offer themselves the ability to break out
> of a different loop (no continue here), one must create another
> try/except clause, further indenting, and causing nontrivial try/except
> overhead inside nested loops.
Ah well, that criticism applies to my suggestion, too. However, I suspect any
such implementation is going to need to use exceptions for the guts of the flow
control, even if that use isn't visible to the programmer.
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.blogspot.com
More information about the Python-Dev
mailing list