foreach() behavior on ranges

frame frame86 at live.com
Tue Aug 24 10:05:34 UTC 2021


On Tuesday, 24 August 2021 at 09:26:20 UTC, jfondren wrote:

> I think you strayed from the beaten path, in a second way, as 
> soon as your range's lifetime escaped a single expression, to 
> be possibly used in two foreach loops. With ranges, as you do 
> more unusual things, you're already encouraged to use a more 
> advanced range. And ranges already have caveats for surprising 
> behavior, like map/filter interactions that redundantly execute 
> code. So I see this as a documentation problem. The current 
> behavior of 'if you break then the next foreach gets what you 
> broke on' is probably a desirable behavior for some uses:

Yes, I have a special case where a delegate jumps back to the 
range because something must be buffered before it can be 
delivered.

> ```d
> import std;
>
> class MyIntRange {
>     int[] _elements;
>     size_t _offset;
>
>     this(int[] elems) { _elements = elems; }
>
>     bool empty() { return !_elements || _offset >= 
> _elements.length; }
>
>     int front() { return _elements[_offset]; }
>
>     void popFront() { _offset++; }
> }
>
> void main() {
>     auto ns = new MyIntRange([0, 1, 1, 2, 3, 4, 4, 4, 5]);
>     // calls writeln() as many times as there are numbers:
>     while (!ns.empty) {
>         foreach (odd; ns) {
>             if (odd % 2 == 0) break;
>             writeln("odd: ", odd);
>         }
>         foreach (even; ns) {
>             if (even % 2 != 0) break;
>             writeln("even: ", even);
>         }
>     }
> }
> ```

That is just weird. It's not logical and a source of bugs. I 
mean, we should use foreach() to avoid loop-bugs. Then it's a 
desired behavior to rely on that?


More information about the Digitalmars-d-learn mailing list