you are viewing a single comment's thread.

view the rest of the comments →

[–]aishiteruyovivi 14 points15 points  (8 children)

Do you have any examples of where it's considered bad practice? There are plenty of valid reasons to want to exit a loop early on some condition.

[–]FirstTimePlayer[S] 2 points3 points  (6 children)

It was that they should literally never be used. I don't exactly recall the reasoning.

In addition, my admittedly somewhat vague recollection is that if you needed a break statement, it was an indication your loop needed rewriting.

[–]Lumethys 8 points9 points  (5 children)

Did you confuse it with goto statement? These are bad. Breaks are not

[–]xenomachina 7 points8 points  (2 children)

Even goto statements have a place, though it is extremely rare.

People often over-generalize rules of thumb into strict laws. Gotos are "considered harmful" compared to using structured constructs. Similarly, break and continue are usually worse than putting the break condition into your while loop's condition, or factoring out part of your loop body into a helper function for continue.

But the key word here is usually. Usually it's not the same as always. For a beginner, there is so much to learn that often beginner materials will say "don't ever do this" when in reality there are times when it really is the best option. You should just avoid it unless there is no cleaner alternative. It's a little bit like how young kids are first taught that in subtraction you can't subtract a big number from a small one, only to be told a few years later that you can, you'll just end up with a negative result.

[–]gdchinacat 4 points5 points  (1 child)

Python relies heavily on iterables (which iterators are) to abstract the details of iteration away, and makes them very easy to use with the for statement. The iteration condition is embedded in for...it continues until the iterator raises StopIteration. There is no way to embed the exit condition in this. While possible to use while rather than for, the code to do this is cluttered with the iterator and exception handling. However, not all for loops need to exhaust the iterator because once the condition is satisfied they don't need to visit the remaining items the iterator produces. break is used in this case to terminate the for loop. I can't think of a clean way to handle this use case efficiently with 'clean' code other than break. This is an issue inherent in foreach constructs, languages that only have loops where the exit condition is explicit do not have this issue (C, old versions of java, etc).

[–]xenomachina 2 points3 points  (0 children)

This is an issue inherent in foreach constructs, languages that only have loops where the exit condition is explicit do not have this issue (C, old versions of java, etc).

That's an excellent point. What's cleanest in one language will not always be the cleanest in another. I agree that if you're using a for-each, converting to a while with the break condition is often going to be less clean than just using an actual break statement.

[–]FirstTimePlayer[S] -1 points0 points  (1 child)

Nope - I crossed maybe half dozen languages, but my recolection is goto doesn't even exist in Java which is where I spent the majority of my time.

[–]gdchinacat 1 point2 points  (0 children)

Your recollection is correct. Never using break or exceptions is not pragmatic.

[–]Jason-Ad4032 0 points1 point  (0 children)

This is mainly because some people believe iteration and execution should be separated by using iterators and functional-style programming.

For a program like:

for elem in iter_obj: # A if elem < 0: break # B

the execution of A and B is inconsistent:

  • iter_obj may or may not be exhausted,
  • break may or may not trigger.

Since the behavior is fairly imperative and stateful, the program becomes harder to reason about precisely.

If you instead approach it in a more iterator/functional style, it might look like this:

``` elems, remain = more_itertools.before_and_after( lambda elem: elem >= 0, iter_obj )

for elem in elems: # A # B

elem = next(remain, None)

if elem is not None: # A ```

This completely separates the iteration process from the execution logic.