View mode: basic / threaded / horizontal-split · Log in · Help
May 16, 2012
Re: DMD Bug or not? foreach over struct range
"Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message 
news:mailman.828.1337154007.24740.digitalmars-d-learn@puremagic.com...
> On Wednesday, May 16, 2012 03:29:23 Nick Sabalausky wrote:
>> "Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message
>> news:mailman.826.1337151940.24740.digitalmars-d-learn@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.
May 16, 2012
Re: DMD Bug or not? foreach over struct range
Actually, I think I'm going to move this over to "digitalmars.D". Seems a 
more appropriate place at this point.
May 16, 2012
Re: DMD Bug or not? foreach over struct range
On Wednesday, 16 May 2012 at 20:50:55 UTC, Nick Sabalausky wrote:

> 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.

 I remember going over hard and long over that section. I think 
it's deliberate.

 Range can refer to many things, and I'm assuming array is one of 
them. So... If the array is consumed when using foreach, that 
seems dump right? (An array in the end is just a small struct 
afterall...)

---
int[] x = [1,2,3];
foreach(i; x) {
 //stuff
}

 assert(x.length == 0, "Should have been consumed!");
---

 Structs being value types are by value and so are copied, not 
referenced. Although referencing a copy does seem a bit silly...

int[] x = [1,2,3];
foreach(ref i; x) {
 i = 10;
}

assert(x == [10,10,10], "But i changed them to 10!!");

--

 That means that foreach(ref; ref) if it's considered (And I 
think it makes sense to) would work for structs in these few 
cases. (Course you'd still consume dynamic arrays that way)

 Something stream based as I've seen in std.stream are classes, 
so they are consumed. I'm probably just rambling...
May 17, 2012
Re: DMD Bug or not? foreach over struct range
On Wed, 16 May 2012 03:20:39 -0400, Jonathan M Davis <jmdavisProg@gmx.com>  
wrote:

> On Wednesday, May 16, 2012 09:15:06 bearophile wrote:
>> Nick Sabalausky:
>> > It seems that foreach is iterating over an implicit copy of
>> > 'foo' instead of
>> > 'foo' itself. Is this correct behavior, or a DMD bug?
>>
>> This program prints "[11, 21, 31]" so for fixed-size arrays (that
>> are values as much as structs) it doesn't perform a copy:
>>
>>
>> import std.stdio;
>> void main() {
>>       int[3] a = [10, 20, 30];
>>       foreach (ref x; a)
>>           x++;
>>       writeln(a);
>> }
>
> It probably slices the array, which would mean that it was operating on a
> dynamic array rather than a static one. But it could just generate  
> different
> code for static arrays.

foreach does *not* use range primitives for arrays, they are special.

-Steve
Next ›   Last »
1 2
Top | Discussion index | About this forum | D home