On 05/08/2020 15:29, Mathew Elman wrote:
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this:

for elem in iterable:
    ...
    if should_break(elem):
        raise SomeException
except SomeException as e:
    handle_break_behaviour(e)
else:
    print("Did not break")

would be sugar for:

try:
    for elem in iterable:
        ...
        if should_break(elem):
            raise SomeException
except SomeException as e:
    handle_break_behaviour(e)
else:
    print("Did not break")
 
I (and others) have suggested this before and no one has said it's a bad option, it's just been ignored, despite seeming to be an intuitive way to accomplish `else` clarity, "labelled" breaks and breaking from multiple loops. Is there a reason that this suggestion is worse / no better than adding special break syntax?


It's certainly a reasonable option.  Indeed, I would consider using the second (currently legal) version in my own code if it seemed appropriate.
Some pros and cons that occur to me (I may be biased, YMMV):
Pros:
    (1) It can cleanly separate the handling of break-type exceptions and other exceptions, if needed.
    (2) It actually clarifies what the dreaded "else" means!
    (3) it allows you to group your "break" cases using exception subclasses (although this is probably OTT for most use cases).
Cons:
    (4) It's more work.  You have to decide what exceptions to use and (most likely) create them.
    (5) It adds the runtime overhead of setting up the "try" and possibly raising the exception.
    (6) Putting (implicitly) try...except around a possibly long for-suite feels bad somehow, even though it wouldn't catch other unwanted exceptions.   
    (7) It does not catch the "zero iterations" case.

If, contra your suggestion, special syntax were to be added, it could use "except" instead of "if ... elif".
For example (this is just doodling, it's not a fully thought-out proposal):

    for x in range(10):
        ...
        if <something happens>:
            break "oops" # under the hood this is a compiled jump, not the raising of an exception
        if <something else happens>:
            break 42
    except "oops":
        <handle something>
    except 42:
        <handle something else>
    except break:
        # catches all "break"s not already explicitly caught
        pass
    else:
        print("Did not break")

Rob Cliffe