On Saturday, 14 November 2015 at 10:46:57 UTC, Alex wrote:
Hi everybody,
I have the following question about "by reference" behavior related to structs.

I have a struct, say S, which contains a member of reference type
struct S
{
    int[] member;
}

and I have a main, for testing:

void main()
{
        S s; // = new S();
        s.arr = [1,2,3];
        writeln(s.arr); //first
        
        S t; // = new S();
        t = s;
        writeln(t.arr); //second
        
        s.arr ~= 4;
        writeln(s.arr); //third
        writeln(t.arr);
}

So, I create a first var of type S, then the second and copied the first into the second. The behavior is like intended, the array inside the struct is copied. But this is a deep copy, as the third block shows. If I change the array in the 's' var, it is not propagated into the 't' var.

Actually, no, it isn't a deep copy. You seem to be missing the fundamentals of how slices (dynamic arrays) work in D. Read Steven's article at [1] for the details. Essentially, you can think of an array in D like this:

struct Array(T) {
    size_t length;
    T* ptr;
}

When you assign s to t, this is what is being copied... *not* the contents of the array. Both arrays will still point into the same memory. Add these two lines immediately after t = s:

writeln(s.arr.ptr);
writeln(t.arr.ptr);

You will see they print the same address. If you try something like this:

s.arr[0] = 100;

You will see the change reflected in both s and t. Add the same two calls to writeln after s ~= 4 and you will see the addresses are now different. Steven's article explains what's going on.


What I want to do is: the propagation of changes to all vars, which are copies of the first one.

The idea which works:
change the definition of S into class and add 'new' on defining the vars.
Then, the example shows the desired behavior.

For what you want to do, this is probably your best option. The other is work with S by pointer, but then you can still use S as a value type. Structs are value types, classes are reference types. If you never want the behavior of a value type for a given type, use a class.


The second idea: implement a postblit into the struct S.
The problem hereby is, how to reference the unique var more then once? How does the postblit looks like? Is it simple a @disable this(this)? But then, I couldn't copy the vars at all... but indeed I don't want to copy them, I rather would like to reference them, if they are intended to mirror the same internal value. Is this idea possible at all?

postblit is often used to make sure you get a deep copy of an array or any reference types:

struct S
{
    int[] arr;
    this(this) {
        arr = arr.dup;
    }
}


[1] http://dlang.org/d-array-article.html

Reply via email to