foreach() behavior on ranges
Steven Schveighoffer
schveiguy at gmail.com
Tue Aug 24 13:02:38 UTC 2021
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.
> There is no way to detect it except the range itself
> tracks its status and does an implicit popFront() if needed - but then
> this whole interface is some kind of useless.
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.
> There is opApply() on the other hand that is designed for foreach() and
> informs via non-0-result if the loop is cancelled - but this means that
> every range must implement it if the range should work in foreach()
> correctly?
`opApply` has to return different values because it needs you to pass
through its instructions to the compiler-generated code. The compiler
has written the delegate to return the message, and so you need to pass
through that information. The non-zero result is significant, not just
non-zero. For instance, if you end with a `break somelabel;` statement,
it has to know which label to go to.
The correct behavior for `opApply` should be, if the delegate returns
non-zero, return that value immediately. It should not be doing anything
else. Would you be happy with a `break somelabel;` actually triggering
output? What if it just continued the loop instead? You don't get to
decide what happens at that point, you are acting as the compiler.
> This is very inconsistent. Either foreach() should deny usage of ranges
> that have no opApply() method or there should be a reset() or cancel()
> method in the interfaces that may be called by foreach() if they are
> implemented.
>
> How do you handle that issue? Are your ranges designed to have this bug
> or do you implement opApply() always?
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?
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
More information about the Digitalmars-d-learn
mailing list