foreach() behavior on ranges

frame frame86 at live.com
Tue Aug 24 18:12:24 UTC 2021


On Tuesday, 24 August 2021 at 13:02:38 UTC, Steven Schveighoffer 
wrote:
> On 8/24/21 4:36 AM, frame wrote:
>> Consider a simple input range that can be iterated with 
>> empty(), front() and popFront(). That is comfortable to use 
>> with foreach() but what if the foreach loop will be cancelled? 
>> If a range isn't depleted yet and continued it will supply the 
>> same data twice on front() in the next use of foreach().
>> 
>> For some reason, foreach() does not call popFront() on a break 
>> or continue statement.
>
> continue calls `popFront`. break does not.

Of course by the next iteration, you are right.

> You can call `popFront` if you need to after the loop, or just 
> before the break. I have to say, the term "useless" does not 
> even come close to describing ranges using foreach in my 
> experience.

I disagree, because foreach() is a language construct and 
therefore it should behave in a logic way. The methods are fine 
in ranges or if something is done manually. But in case of 
foreach() it's just unexpected.

It becomes useless for foreach() because you can't rely on them 
if other code breaks the loop and you need to use that range, 
like in my case. But also for ranges - there is no need for a 
popFront() if it is not called in a logic way. Then even empty() 
could fetch next data if needed. It only makes sense if language 
system code uses it in a strictly order and ensures that this 
order is always assured.


> It's not a bug. So there is no need to "handle" it.
>
> The pattern of using a for(each) loop to align certain things 
> occurs all the time in code. Imagine a loop that is looking for 
> a certain line in a file, and breaks when the line is there. 
> Would you really want the compiler to unhelpfully throw away 
> that line for you?

I don't get this point. If it breaks from the loop then it 
changes the scope anyway, so my data should be already processed 
or copied. What is thrown away here?

>
> And if that is what you want, put `popFront` in the loop before 
> you exit. You can't "unpopFront" something, so this provides 
> the most flexibility.
>
> -Steve

Yes, this is the solution but not the way how it should be. If 
the programmer uses the range methods within the foreach-loop 
then you would expect some bug. There shouldn't be a need to 
manipulate the range just because I break the foreach-loop.

Java, for example just uses next() and hasNext(). You can't run 
into a bug here because one method must move the cursor.

PHP has a rewind() method. So any foreach() would reset the range 
or could clean up before next use of it.

But D just lets your range in an inconsistent state between an 
iteration cycle. This feels just wrong. The next foreach() would 
not continue with popFront() but with empty() again - because it 
even relies on it that a range should be called in a given order. 
As there is no rewind or exit-method, this order should be 
maintained by foreach-exit too, preparing for next use. That's it.

You don't see a bug here?



More information about the Digitalmars-d-learn mailing list