DMD Bug or not? foreach over struct range
Nick Sabalausky
SeeWebsiteToContactMe at semitwist.com
Wed May 16 13:50:17 PDT 2012
"Jonathan M Davis" <jmdavisProg at gmx.com> wrote in message
news:mailman.828.1337154007.24740.digitalmars-d-learn at puremagic.com...
> On Wednesday, May 16, 2012 03:29:23 Nick Sabalausky wrote:
>> "Jonathan M Davis" <jmdavisProg at gmx.com> wrote in message
>> news:mailman.826.1337151940.24740.digitalmars-d-learn at puremagic.com...
>>
>> > No. That's expected. Your range is a value type, so it got copied when
>> > you
>> > used it with foreach.
>>
>> But foreach isn't a function, it's a flow-control statement.
>
> If it _wasn't_ copied, using foreach would consume your range.
Iterating a range normally *does* consume it. And that's expected, as it
should be: Imagine, for example, an input range that read from stdin.
Leaving that range unconsumed would make no sense at all. Actually any input
range can be expected to *not* leave an uniterated copy: if it *could* have
an uniterated copy left behind, it would be a forward range, not an input
range.
> It doesn't, and it would really suck if it did.
Like I said above, it would suck if you use the current foreach over an
input range: Sometimes it might work by pure luck (as in the original
example), but you can expect that for some input ranges it would fail
miserably, because an input range is *not* a forward range and by definition
cannot reliably save a previous state.
Additionally, if you wanted to still have an un-iterated version (of an
actual foreard range, or an input range that you knew to be safe), then
that's trivial:
Foo a;
b = a.save(); // Or "b = a;" if you really know what you're doing.
foreach(elem; a) {}
assert(a.empty);
assert(!b.empty);
Note, however, that there is no such simple way to go the other way around:
to have the current "foreach over a copy" behavior and have access to the
actual iterated range. Maybe if we had "foreach(e; ref range)", but AFAIK we
don't.
Maybe it's just me, but I'd intuitively expect foreach over a range to work
like this:
Range range;
foreach(e; range) {...}
-->
Range range;
for(; !range.empty(); range.popFront())
{
auto e = range.front;
...
}
I was initially open to the idea I may have just misunderstood something,
but I'm becoming more and more convinced that the current "foreach over an
implicit copy" behavior is indeed a bad idea.
I'd love to see Andrei weigh in on this. I'm curious if the example you
pointed out in TDPL made the copy deliberately, or if the effects of that
copy were just an oversight.
More information about the Digitalmars-d-learn
mailing list