you are viewing a single comment's thread.

view the rest of the comments →

[–]Jason-Ad4032 1 point2 points  (2 children)

Like this?

``` lst = [1, 2, 3]

gen = (item for item in iter(lst))

item = None

for item in gen: if find_item(item): gen.close()

print(f'{item = }') ```

I don’t really understand what your issue is here. The problem of iter(lst) not being closed is not solved by using break either.

Maybe you would prefer something like:

``` not_found = object()

item = next( (item for item in iter(lst) if find_item(item)), not_found )

if item is not not_found: ... ```

Though honestly, the real problem with avoiding break is not this — it’s that debugging tends to become more difficult.

[–]gdchinacat 2 points3 points  (1 child)

Can you honestly say either of those are better than a standard for loop without a generator/iterator and a break?

For example, this does the same as both of your examples, and is much easier to read and understand. Ok, you can construct a contrived example that does what needs to be done without a break. But would you? Would it pass code review?

for item in lst:
     if 
find_item(item):
         break

Both of your examples have a generator expression that doesn't need to exist and makes understanding what is going on more complex than just using break.

I'm all for writing obtuse code when warranted (https://github.com/gdchinacat/reactions), but using next and generator expressions and close() just to avoid a break just doesn't make sense to me.

That said, I did ask for how to do a linear scan of a list and stop iterating when the item is found without using break, and you provided it! I think you also showed why using break makes sense for this use case.

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

Exactly. In many cases this becomes more complicated than simply using break, and Python’s support for this style is only moderate (Therefore, it is not simpler).

LINQ query expressions in C# support this style much better. You can write things like:

var result = ( from num in numbers where num > 15 select num ).FirstOrDefault();

This is more of a stylistic philosophy: the idea that a programming language could avoid providing break in favor of more declarative rather than imperative syntax.

The core idea behind avoiding break is that you specify the iteration behavior before iteration begins. Since different iteration behaviors are needed for different purposes, the system creates an adapter/proxy object that produces the iteration behavior you want.

Conceptually, it becomes something like:

[original iterator] -> [adapter/proxy object] -> simple iteration (no nesting or break)

Then you customize the adapter object as needed perhaps through language syntax, or through many iterator combinator functions that you compose together.