[Python-checkins] r56131 - peps/trunk/pep-0000.txt peps/trunk/pep-3136.txt
georg.brandl
python-checkins at python.org
Sat Jun 30 20:31:14 CEST 2007
Author: georg.brandl
Date: Sat Jun 30 20:31:14 2007
New Revision: 56131
Added:
peps/trunk/pep-3136.txt
Modified:
peps/trunk/pep-0000.txt
Log:
Add PEP 3136 by Matt Chisholm, ``Labeled break and continue''.
Modified: peps/trunk/pep-0000.txt
==============================================================================
--- peps/trunk/pep-0000.txt (original)
+++ peps/trunk/pep-0000.txt Sat Jun 30 20:31:14 2007
@@ -103,6 +103,7 @@
S 3124 Overloading, Generic Functions, Interfaces Eby
S 3134 Exception Chaining and Embedded Tracebacks Yee
S 3135 New Super Spealman, Delaney
+ S 3136 Labeled break and continue Chisholm
S 3141 A Type Hierarchy for Numbers Yasskin
Finished PEPs (done, implemented in Subversion)
@@ -505,6 +506,7 @@
SR 3133 Introducing Roles Winter
S 3134 Exception Chaining and Embedded Tracebacks Yee
S 3135 New Super Spealman, Delaney
+ S 3136 Labeled break and continue Chisholm
S 3141 A Type Hierarchy for Numbers Yasskin
@@ -541,6 +543,7 @@
Cannon, Brett brett at python.org
Carlson, Josiah jcarlson at uci.edu
Carroll, W Isaac icarroll at pobox.com
+ Chisholm, Matt matt-python at theory.org
Coghlan, Nick ncoghlan at gmail.com
Cole, Dave djc at object-craft.com.au
Craig, Christopher python-pep at ccraig.org
Added: peps/trunk/pep-3136.txt
==============================================================================
--- (empty file)
+++ peps/trunk/pep-3136.txt Sat Jun 30 20:31:14 2007
@@ -0,0 +1,485 @@
+PEP: 3136
+Title: Labeled break and continue
+Version: $Revision$
+Last-Modified: $Date$
+Author: Matt Chisholm <matt-python at theory.org>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 30-Jun-2007
+Python-Version: 3.1
+Post-History:
+
+
+Abstract
+========
+
+This PEP proposes support for labels in Python's ``break`` and
+``continue`` statements. It is inspired by labeled ``break`` and
+``continue`` in other languages, and the author's own infrequent but
+persistent need for such a feature.
+
+
+Introduction
+============
+
+The ``break`` statement allows the programmer to terminate a loop
+early, and the ``continue`` statement allows the programmer to move to
+the next iteration of a loop early. In Python currently, ``break``
+and ``continue`` can apply only to the innermost enclosing loop.
+
+Adding support for labels to the ``break`` and ``continue`` statements
+is a logical extension to the existing behavior of the ``break`` and
+``continue`` statements. Labeled ``break`` and ``continue`` can
+improve the readability and flexibility of complex code which uses
+nested loops.
+
+For brevity's sake, the examples and discussion in this PEP usually
+refers to the ``break`` statement. However, all of the examples and
+motivations apply equally to labeled ``continue``.
+
+
+Motivation
+==========
+
+If the programmer wishes to move to the next iteration of an outer
+enclosing loop, or terminate multiple loops at once, he or she has a
+few less-than elegant options.
+
+Here's one common way of imitating labeled ``break`` in Python (For
+this and future examples, ``...`` denotes an arbitrary number of
+intervening lines of code)::
+
+ for a in a_list:
+ time_to_break_out_of_a = False
+ ...
+ for b in b_list:
+ ...
+ if condition_one(a, b):
+ break
+ ...
+ if condition_two(a, b):
+ time_to_break_out_of_a = True
+ break
+ ...
+ if time_to_break_out_of_a:
+ break
+ ...
+
+
+This requires five lines and an extra variable,
+``time_to_break_out_of_a``, to keep track of when to break out of the
+outer (a) loop. And those five lines are spread across many lines of
+code, making the control flow difficult to understand.
+
+This technique is also error-prone. A programmer modifying this code
+might inadvertently put new code after the end of the inner (b) loop
+but before the test for ``time_to_break_out_of_a``, instead of after
+the test. This means that code which should have been skipped by
+breaking out of the outer loop gets executed incorrectly.
+
+This could also be written with an exception. The programmer would
+declare a special exception, wrap the inner loop in a try, and catch
+the exception and break when you see it::
+
+ class BreakOutOfALoop(Exception): pass
+
+ for a in a_list:
+ ...
+ try:
+ for b in b_list:
+ ...
+ if condition_one(a, b):
+ break
+ ...
+ if condition_two(a, b):
+ raise BreakOutOfALoop
+ ...
+ except BreakOutOfALoop:
+ break
+ ...
+
+
+Again, though; this requires five lines and a new, single-purpose
+exception class (instead of a new variable), and spreads basic control
+flow out over many lines. And it breaks out of the inner loop with
+``break`` and out of the other loop with an exception, which is
+inelegant. [#toowtdi]_
+
+This next strategy might be the most elegant solution, assuming
+condition_two() is inexpensive to compute::
+
+ for a in a_list:
+ ...
+ for b in b_list:
+ ...
+ if condition_one(a, b):
+ break
+ ...
+ if condition_two(a, b):
+ break
+ ...
+ if condition_two(a, b)
+ break
+ ...
+
+
+Breaking twice is still inelegant. This implementation also relies on
+the fact that the inner (b) loop bleeds b into the outer for loop,
+which (although explicitly supported) is both surprising to novices,
+and in my opinion counter-intuitive and poor practice.
+
+The programmer must also still remember to put in both breaks on
+condition two and not insert code before the second break. A single
+conceptual action, breaking out of both loops on condition_two(),
+requires four lines of code at two indentation levels, possibly
+separated by many intervening lines at the end of the inner (b) loop.
+
+
+Other languages
+---------------
+
+Now, put aside whatever dislike you may have for other programming
+languages, and consider the syntax of labeled ``break`` and
+``continue``. In Perl::
+
+ ALOOP: foreach $a (@a_array){
+ ...
+ BLOOP: foreach $b (@b_array){
+ ...
+ if (condition_one($a,$b)){
+ last BLOOP; # same as plain old last;
+ }
+ ...
+ if (condition_two($a,$b)){
+ last ALOOP;
+ }
+ ...
+ }
+ ...
+ }
+
+
+(Notes: Perl uses ``last`` instead of ``break``. The BLOOP labels
+could be omitted; ``last`` and ``continue`` apply to the innermost
+loop by default.)
+
+PHP uses a number denoting the number of loops to break out of, rather
+than a label::
+
+ foreach ($a_array as $a){
+ ....
+ foreach ($b_array as $b){
+ ....
+ if (condition_one($a, $b)){
+ break 1; # same as plain old break
+ }
+ ....
+ if (condition_two($a, $b)){
+ break 2;
+ }
+ ....
+ }
+ ...
+ }
+
+
+C/C++, Java, and Ruby all have similar constructions.
+
+The control flow regarding when to break out of the outer (a) loop is
+fully encapsulated in the ``break`` statement which gets executed when
+the break condition is satisfied. The depth of the break statement
+does not matter. Control flow is not spread out. No extra variables,
+exceptions, or re-checking or storing of control conditions is
+required. There is no danger that code will get inadvertently
+inserted after the end of the inner (b) loop and before the break
+condition is re-checked inside the outer (a) loop. These are the
+benefits that labeled ``break`` and ``continue`` would bring to
+Python.
+
+
+What this PEP is not
+====================
+
+This PEP is not a proposal to add GOTO to Python. GOTO allows a
+programmer to jump to an arbitrary block or line of code, and
+generally makes control flow more difficult to follow. Although
+``break`` and ``continue`` (with or without support for labels) can be
+considered a type of GOTO, it is much more restricted. Another Python
+construct, ``yield``, could also be considered a form of GOTO -- an
+even less restrictive one. The goal of this PEP is to propose an
+extension to the existing control flow tools ``break`` and
+``continue``, to make control flow easier to understand, not more
+difficult.
+
+Labeled ``break`` and ``continue`` cannot transfer control to another
+function or method. They cannot even transfer control to an arbitrary
+line of code in the current scope. Currently, they can only affect
+the behavior of a loop, and are quite different and much more
+restricted than GOTO. This extension allows them to affect any
+enclosing loop in the current name-space, but it does not change their
+behavior to that of GOTO.
+
+
+Specification
+=============
+
+Under all of these proposals, ``break`` and ``continue`` by themselves
+will continue to behave as they currently do, applying to the
+innermost loop by default.
+
+
+Proposal A - Explicit labels
+----------------------------
+
+The for and while loop syntax will be followed by an optional ``as``
+or ``label`` (contextual) keyword [#keyword]_ and then an identifier,
+which may be used to identify the loop out of which to break (or which
+should be continued).
+
+The ``break`` (and ``continue``) statements will be followed by an
+optional identifier that refers to the loop out of which to break (or
+which should be continued). Here is an example using the ``as``
+keyword::
+
+ for a in a_list as a_loop:
+ ...
+ for b in b_list as b_loop:
+ ...
+ if condition_one(a, b):
+ break b_loop # same as plain old break
+ ...
+ if condition_two(a, b):
+ break a_loop
+ ...
+ ...
+
+Or, with ``label`` instead of ``as``::
+
+ for a in a_list label a_loop:
+ ...
+ for b in b_list label b_loop:
+ ...
+ if condition_one(a, b):
+ break b_loop # same as plain old break
+ ...
+ if condition_two(a, b):
+ break a_loop
+ ...
+ ...
+
+
+This has all the benefits outlined above. It requires modifications
+to the language syntax: the syntax of ``break`` and ``continue``
+syntax statements and for and while statements. It requires either a
+new conditional keyword ``label`` or an extension to the conditional
+keyword ``as``. [#as]_ It is unlikely to require any changes to
+existing Python programs. Passing an identifier not defined in the
+local scope to ``break`` or ``continue`` would raise a NameError.
+
+
+Proposal B - Numeric break & continue
+-------------------------------------
+
+Rather than altering the syntax of ``for`` and ``while`` loops,
+``break`` and ``continue`` would take a numeric argument denoting the
+enclosing loop which is being controlled, similar to PHP.
+
+It seems more Pythonic to me for ``break`` and ``continue`` to refer
+to loops indexing from zero, as opposed to indexing from one as PHP
+does.
+
+::
+
+ for a in a_list:
+ ...
+ for b in b_list:
+ ...
+ if condition_one(a,b):
+ break 0 # same as plain old break
+ ...
+ if condition_two(a,b):
+ break 1
+ ...
+ ...
+
+Passing a number that was too large, or less than zero, or non-integer
+to ``break`` or ``continue`` would (probably) raise an IndexError.
+
+This proposal would not require any changes to existing Python
+programs.
+
+
+Proposal C - The reduplicative method
+-------------------------------------
+
+The syntax of ``break`` and ``continue`` would be altered to allow
+multiple ``break`` and continue statements on the same line. Thus,
+``break break`` would break out of the first and second enclosing
+loops.
+
+::
+
+ for a in a_list:
+ ...
+ for b in b_list:
+ ...
+ if condition_one(a,b):
+ break # plain old break
+ ...
+ if condition_two(a,b):
+ break break
+ ...
+ ...
+
+
+This would also allow the programmer to break out of the inner loop
+and continue the next outermost simply by writing ``break continue``,
+[#breakcontinue]_ and so on. I'm not sure what exception would be
+raised if the programmer used more ``break`` or ``continue``
+statements than existing loops (perhaps a SyntaxError?).
+
+I expect this proposal to get rejected because it will be judged too
+difficult to understand.
+
+This proposal would not require any changes to existing Python
+programs.
+
+
+Proposal D - Explicit iterators
+-------------------------------
+
+Rather than embellishing for and while loop syntax with labels, the
+programmer wishing to use labeled breaks would be required to create
+the iterator explicitly and assign it to a identifier if he or she
+wanted to ``break`` out of or ``continue`` that loop from within a
+deeper loop.
+
+::
+
+ a_iter = iter(a_list)
+ for a in a_iter:
+ ...
+ b_iter = iter(b_list)
+ for b in b_iter:
+ ...
+ if condition_one(a,b):
+ break b_iter # same as plain old break
+ ...
+ if condition_two(a,b):
+ break a_iter
+ ...
+ ...
+
+
+Passing a non-iterator object to ``break`` or ``continue`` would raise
+a TypeError; and a nonexistent identifier would raise a NameError.
+This proposal requires only one extra line to create a labeled loop,
+and no extra lines to break out of a containing loop, and no changes
+to existing Python programs.
+
+
+Proposal E - Explicit iterators and iterator methods
+----------------------------------------------------
+
+This is a variant of Proposal D. Iterators would need be created
+explicitly if anything other that the most basic use of ``break`` and
+``continue`` was required. Instead of modifying the syntax of
+``break`` and ``continue``, ``.break()`` and ``.continue()`` methods
+could be added to the Iterator type.
+
+::
+
+ a_iter = iter(a_list)
+ for a in a_iter:
+ ...
+ b_iter = iter(b_list)
+ for b in b_iter:
+ ...
+ if condition_one(a,b):
+ b_iter.break() # same as plain old break
+ ...
+ if condition_two(a,b):
+ a_iter.break()
+ ...
+ ...
+
+
+I expect that this proposal will get rejected on the grounds of sheer
+ugliness. However, it requires no changes to the language syntax
+whatsoever, nor does it require any changes to existing Python
+programs.
+
+
+Implementation
+==============
+
+I have never looked at the Python language implementation itself, so I
+have no idea how difficult this would be to implement. If this PEP is
+accepted, but no one is available to write the feature, I will try to
+implement it myself.
+
+
+Footnotes
+=========
+
+.. [#toowtdi] Breaking some loops with exceptions is inelegant because
+ it's a violation of There's Only One Way To Do It.
+
+.. [#keyword] Or really any new contextual keyword that the community
+ likes: ``as``, ``label``, ``labeled``, ``loop``, ``name``, ``named``,
+ ``walrus``, whatever.
+
+.. [#as] The use of ``as`` in a similar context has been proposed here,
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1714448&group_id=5470&atid=355470
+ but to my knowledge this idea has not been written up as a PEP.
+
+.. [#breakcontinue] To continue the Nth outer loop, you would write
+ break N-1 times and then continue. Only one ``continue`` would be
+ allowed, and only at the end of a sequence of breaks. ``continue
+ break`` or ``continue continue`` makes no sense.
+
+
+Resources
+=========
+
+This issue has come up before, although it has never been resolved, to
+my knowledge.
+
+* `labeled breaks`__, on comp.lang.python, in the context of
+ ``do...while`` loops
+
+ __ http://groups.google.com/group/comp.lang.python/browse_thread/thread/6da848f762c9cf58/979ca3cd42633b52?lnk=gst&q=labeled+break&rnum=3#979ca3cd42633b52
+
+* `break LABEL vs. exceptions + PROPOSAL`__, on python-list, as
+ compared to using Exceptions for flow control
+
+ __ http://mail.python.org/pipermail/python-list/1999-September/#11080
+
+* `Named code blocks`__ on python-list, a suggestion motivated by the
+ desire for labeled break / continue
+
+ __ http://mail.python.org/pipermail/python-list/2001-April/#78439
+
+* `mod_python bug fix`__ An example of someone setting a flag inside
+ an inner loop that triggers a continue in the containing loop, to
+ work around the absence of labeled break and continue
+
+ __ http://mail-archives.apache.org/mod_mbox/httpd-python-cvs/200511.mbox/%3C20051112204322.4010.qmail@minotaur.apache.org%3E
+
+
+Copyright
+=========
+
+This document has been placed in the public domain.
+
+
+
+..
+ Local Variables:
+ mode: indented-text
+ indent-tabs-mode: nil
+ sentence-end-double-space: t
+ fill-column: 70
+ coding: utf-8
+ End:
More information about the Python-checkins
mailing list