foreach over pointers OR foreach that mutates the iterator

Las via Digitalmars-d digitalmars-d at puremagic.com
Wed Jan 25 08:15:49 PST 2017


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?


More information about the Digitalmars-d mailing list