foreach over pointers OR foreach that mutates the iterator
ZombineDev via Digitalmars-d
digitalmars-d at puremagic.com
Thu Jan 26 03:32:09 PST 2017
On Wednesday, 25 January 2017 at 16:15:49 UTC, Las wrote:
> So the reference says that (when range has the properties)
> `foreach (e; range) { ... }` is equivalent to:
> for (auto __r = range; !__r.empty; __r.popFront())
> {
> auto e = __r.front;
> ...
> }
>
> Though this isn't always true, as when I use this struct:
> struct S {
> int front = 10;
> void popFront() {
> --front;
> }
> @property bool empty() {
> return front == 0;
> }
> }
>
> then I can do this:
> void main() {
> S s;
> auto p = &s;
> p.popFront;
> writeln(p.front);
> }
>
> But not this:
> void main() {
> S s;
> auto p = &s;
> foreach(i; p)
> writeln(i);
> }
>
> x.d(18): Error: invalid foreach aggregate p
> Failed: ["dmd", "-v", "-c",
> "-of/tmp/.rdmd-1000/rdmd-x.d-032B33C4A922C519594F67AF08DBF6C9/objs/x.o", "x.d", "-I."]
>
> Why should this work? Because some times I want foreach to
> modify the iterator, because some times I like to have an inner
> foreach that uses the same iterator as the outer one, to
> effectively still iterate over the same range, but change the
> contents of the loop.
>
> Bad example:
> foreach(i; &range) {
> writeln(i);
> if(i > 2) foreach(i; &range) {
> writeln(i * 3);
> if(i < 10)
> break;
> }
> }
>
> This loop would change behavior each time one of the 'if's pass.
>
> An alternative would be to implement a new foreach, perhaps
> &foreach, that does this instead:
> for (/+ NB: We are not copying the range! +/; !range.empty;
> range.popFront())
> {
> auto e = range.front;
> ...
> }
>
> Related:
> UFCS does not work on pointers, which matters because of
> std.range.primitives.
>
> Thoughts?
Not sure if this is a bug in isInputRange or foreach, but they
should work consistently. Anyway, another solution is to use
refRange:
void main() {
import std.range : refRange;
S s;
auto p = refRange(&s);
foreach(i; p)
writeln(i);
}
That way you don't need to dereference 'p' everytime you want to
iterate over it. Plus, it should compose well with other range
wrappers / algorithms.
More information about the Digitalmars-d
mailing list