how is this array subtyping inside struct (bug?) possible?

Paul Backus snarwin at gmail.com
Sun Aug 9 20:30:35 UTC 2020


On Sunday, 9 August 2020 at 18:45:07 UTC, mw wrote:
> Hi,
>
> I want to share an array among a number of structs, with 
> subtyping, I tried this, and find some strange behavior:
>
> ```
> class SharedArray(T) {
>   public T[] array;
>   alias array this;  // subtyping
> }
>
> alias Filenames = SharedArray!(string);
>
> struct S {
>   Filenames fns;
>   void alloc() {
>     fns = new Filenames();
>   }
> }
>
> void main(string[] args) {
>   S s0;
>   s0.alloc();
>   s0.fns ~= "abc";
>
>   foreach (i; 0..3) {
>     S* s1 = new S();
>     *s1 = s0;   //  copy the value from s0 to *s1
>     writeln(s0.fns);
>   }
> }
> ```
>
> program output:
> ```
> ["abc"]
> []
> []
> ```
>
> why s0.fns changed after copy the value from s0 to *s1?
>
> Is this a bug?

No, it's not a bug, it's just a weird quirk of how `alias this` 
interacts with reference types like classes.

When you pass a range to `writeln`, it will iterate the range 
using `front` and `popFront` in order to print each of the 
elements. Doing this consumes the range.

Normally, that's not a problem, because writeln takes its 
arguments by value, so any range you pass to it will be copied, 
and only the copy will be consumed. However, because you've made 
your `Filenames` class into an input range using `alias this`, 
and classes are reference types, consuming a copy of the range 
also consumes the original.

The solution is to use the `save` function from `std.range` to 
create an independent copy of the range for `writeln` to iterate:

     import std.range;
     writeln(s0.fns.save);


More information about the Digitalmars-d mailing list