how is this array subtyping inside struct (bug?) possible?
Steven Schveighoffer
schveiguy at gmail.com
Mon Aug 10 19:30:18 UTC 2020
On 8/10/20 2:36 PM, mw wrote:
> On Monday, 10 August 2020 at 18:29:56 UTC, mw wrote:
>> and where in this doc on range:
>>
>> https://tour.dlang.org/tour/en/basics/ranges
>>
>> it is mentioned that: the length property of the range will be changed
>> after the range is "consumed" by foreach loop?
>>
>> ```
>> foreach (element; range)
>> {
>> // Loop body...
>> }
>> it's internally rewritten similar to the following:
>>
>> for (auto __rangeCopy = range;
>> !__rangeCopy.empty;
>> __rangeCopy.popFront())
>> {
>> auto element = __rangeCopy.front;
>> // Loop body...
>> }
>> ```
>
> And wait, ... did I saw "__rangeCopy" here? it should be a *copy*?!
>
>
In your code, the type of "range" is SharedArray!(string) which is a
class or *reference type*.
So let's follow along what happens:
SharedArray!(string) fns;
for(auto __rangeCopy = fns;
// the above makes a copy of a *class reference*, which means it does
not make a copy of the *array data* or even the array reference. It's
like copying a pointer to the array.
!__rangeCopy.empty;
// SharedArray(T) does not have empty member, so this forwards to the
array, it's like saying:
// !__rangeCopy.array.empty
__rangeCopy.popFront())
// This is equivalent to __rangeCopy.array.popFront, which alters the
array inside the ONE SHARED class instance.
So now, what ends up happening is because fns and the __rangeCopy are
actually just copies of a pointer, or class reference, when you iterate
one, the other is iterated.
How to fix? extract the array before iterating:
writeln(s0.fns.array);
This will make a copy of the array reference itself, and iterate that.
This is precisely why classes should never be ranges.
-Steve
More information about the Digitalmars-d
mailing list