foreach() behavior on ranges
frame
frame86 at live.com
Wed Aug 25 08:31:00 UTC 2021
On Tuesday, 24 August 2021 at 21:15:02 UTC, Steven Schveighoffer
wrote:
> If you have a for loop:
>
> ```d
> int i;
> for(i = 0; i < someArr.length; ++i)
> {
> if(someArr[i] == desiredValue) break;
> }
> ```
>
> You are saying, "compiler, please execute the `++i` when I
> break from the loop because I already processed that one". How
> can that be expected? I would *never* expect that. When I
> break, it means "stop the loop, I'm done", and then I use `i`
> which is where I expected it to be.
I get your point, you see foreach() as raw translate to the
for-loop and I'm fine with that. To automatically popFront() on
break also is only a suggestion if there is no other mechanism to
the tell the range we have cancelled it.
>
>> 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.
>
> There is no problem with the ordering. What seems to be the
> issue is that you aren't used to the way ranges work.
Ehm, no...
-> empty()
-> front()
-> popFront()
-> empty()
-> front()
break;
-> empty();
-> front();
clearly violates the order for me.
Well, nobody said that we must move on the range - but come on...
> What's great about D is that there is a solution for you:
>
> ```d
> struct EagerPopfrontRange(R)
> {
> R source;
> ElementType!R front;
> bool empty;
> void popFront() {
> if(source.empty) empty = true;
> else {
> front = source.front;
> source.popFront;
> }
> }
> }
>
> auto epf(R)(R inputRange) {
> auto result = EagerPopfrontRange!R(inputRange);
> result.popFront; // eager!
> return result;
> }
>
> // usage
> foreach(v; someRange.epf) { ... }
> ```
>
> Now if you break from the loop, the original range is pointing
> at the element *after* the one you last were processing.
This is nice. But foreach() should do it automatically - avoiding
this.
foreach() should be seen as a special construct that does that,
not just a dumb alias for the for-loop. Why? Because it is a
convenient language construct and usage should be easy. Again,
there should be no additional popFront() just because I break the
loop.
> I'm surprised you bring PHP as an example, as it appears their
> foreach interface works EXACTLY as D does:
Yeah, but the point is, there is a rewind() method. That is
called every time on foreach().
More information about the Digitalmars-d-learn
mailing list