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