Break and continue could have arguments

break and continue could have arguments, that determine from which loop (starting counting from the loop where break is to out) program should break out or take new value for variable.

for i1 in range(3):
    for i2 in range(3):
        for i3 in range(3):
            print(i1,i2,i3)
            if i1==i2==i3:
                break(1)

outputs:

0 0 0
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
for i1 in range(3):
    for i2 in range(3):
        for i3 in range(3):
            print(i1,i2,i3)
            if i1==i2==i3:
                break(2)

outputs:

0 0 0
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
for i1 in range(3):
    for i2 in range(3):
        for i3 in range(3):
            print(i1,i2,i3)
            if i1==i2==i3:
                break(3)

outputs:

0 0 0

This is very fragile. Consider your second example:

for i1 in range(3):
    for i2 in range(3):
        for i3 in range(3):
            print(i1,i2,i3)
            if i1==i2==i3:
                break(2)

Suppose I insert another loop (not as uncommon as you might think). Now
I must renumber all the breaks inside the loop.

A less fragile approach would be labels, something like this:

PRIMARY:
  for i1 in range(3):
    SECONDARY:
      for i2 in range(3):
        INNERMOST:
          for i3 in range(3):
            print(i1,i2,i3)
            if i1==i2==i3:
                break(SECONDARY)

Ignoring that this particular syntax doesn’t quite fit Python, now the
loop you intend to break from has a stable name which adding more
structure such as an additional loop will not change. Perl’s got
something like this.

Cheers,
Cameron Simpson cs@cskk.id.au

I think it could have many possibilities to use it. With number like in my first post or with labels like in your example.

for i1 in range(n):
    for i2 in range(n):
        for i3 in range(n):
            print(i1,i2,i3)
            if f(i1,i2,i3):
                break(3)

Is more easily readable than

flag = False
for i1 in range(n):
    for i2 in range(n):
        for i3 in range(n):
            print(i1,i2,i3)
            if f(i1,i2,i3):
                flag=True
                break
        if flag:
            break
    if flag:
        break

In this particular case, the use of itertools’ product and takewhile
would result in more readable code than nested loops. For more complex
cases, one should move the inner loops out to a separate funtion
and return from it.

IMHO breaking outter block, if ever accepted into Python, should base
on names instead of number. We could use a new keyword e.g. block RABBIT:
which both to name it for breaking and introducing a new lexical scope.
While we’re at it, why not go ahead and add goto as well (-;

In other words, this seems to be nice-to-have, but seems to conflict
with the Zen of Python:

Simple is better than complex.
Flat is better than nested.
There should be one-- and preferably only one --obvious way to do it.

Agree.
But maybe these ways are not equal, maybe the 1 with break(3), could be compiled to run faster than the solution with flag, because checking flag for every new value of i2 and i1 takes time.

Pycharm or other idea could do it automatically after new loop has been added.

I’d argue the obvious way to do it here is the return statement.

As for the numberings, they are basically local magic numbers
and changing them would make the diff hella confusing.

It does not work with every program. Following programm

n=0
for i3 in range(n):
    for i2 in range(n):
        for i1 in range(n):
            if F(i1,i2,i3)>0:
                break(2)
            if F(i1,i2,i3)>1:
                break(3)
            if F(i1,i2,i3)>2:
                continue(2)
            if F(i1,i2,i3)>3:
                continue(3)
            n+=F(i1,i2,i3)
        n+=F(i3,i2)
    n+=F(i3)

is very hard and ugly without using flags, function calls, break with argument or continue with argument.

1 Like

You’re right, this can be the most readable form (among all variations I came up with).

1 Like

see also PEP 3136 -- Labeled break and continue | Python.org

2 Likes

B is very similar to my idea.
Otherwise I would like E more, but it does not work with while loops with no iterator.

Addition to my idea: argument of break would count every statement that causes indent (if,try,else,except,finally,with). So it could be used to break out from other blocks as well.
I think the reason why current version break does not break if’s is that it can break only 1 block and if’s would stay on way and not let to break loop-blocks.

With current version of python is impossible to make a program with following or better bytecode:

LOAD_GLOBAL (A)#LABEL1
LOAD_FAST (x)
CALL_FUNCTION 1
STORE_FAST (x)
LOAD_GLOBAL (B)#LABEL2
LOAD_FAST (x)
CALL_FUNCTION 1
STORE_FAST (x)
LOAD_GLOBAL (C)#LABEL3
LOAD_FAST (x)
CALL_FUNCTION 1
STORE_FAST (x)
COMPARE x>2
JUMP_IF #LABEL1
COMPARE x>1
JUMP_IF #LABEL2
COMPARE x>0
JUMP_IF #LABEL3
LOAD_FAST (x)
RETURN_VALUE

but with argumented-break it is:

while True:
    x=A(x)
    while True:
        x=B(x)
        while True:
            x=C(x)
            if x>2:
                break(3)#goto x=A(x)
            if x>1:
                break(2)#goto x=B(x)
            if x>0:
                break(1)#goto x=C(x)
            else:
                return(x)
´´´

Well found, Dennis. I would also note GvR’s comments in the rejection of this idea:
“code so complicated to require this feature is very rare. In most cases there are existing work-arounds that produce clean code”
and
“this has been brought up and rejected many times before”
and
“My expectation that the feature will be abused more than it will be used right”
and (my favourite)
“There is real value in having a small language”

2 Likes