On Saturday, 24 November 2012 at 20:47:17 UTC, Era Scarecrow
wrote:
On Friday, 23 November 2012 at 22:31:46 UTC, Rob T wrote:
That's VERY interesting indeed and originally I had no idea it
would do this without a custom opAssign at each level.
This kind of behavior *really* needs to be documented in
precise detail, it's rather critical to know.
It IS documented. TDPL - pg. 248
[quote]
The second step (the part with 'transitive field') of the
postblit copy process deserves a special mention. The rationale
for that behavior is [i]encapsulation[/i]-the postblit
constructor of a struct object must be called even when the
struct is embedded in another struct object. Consider, for
example, that we make Widget a member of another struct, which
in turn is a member of yet another struct:
(included from pg. 246)
[code]
struct Widget {
private int[] array;
this(uint length) {
array = new int[length];
}
// postblit constructor
this(this){
array = array.dup;
}
//As Before
int get(size_t offset) { return array[offset]; }
void set(size_t offset, int value) { array[offset] = value; }
}
struct Widget2 {
Widget w1;
int x;
}
struct Widget3 {
Widget2 w2;
string name;
this(this) {
name = name ~ " (copy)";
}
}
[/code]
Now, if you want to copy around objects that contain Widgets,
it would be pretty bad if the compiler forgot to properly copy
the Widget subobjects. That's why when copying objects of type
Widget2, a call to this(this) is issued for the w subobject,
even though Widget2 does not intercept copying at all. Also,
when copying objects of type Widget3, again this(this) is
invoked for the field w1 of field w2. To Clarify:
[code]
unittest {
Widget2 a;
a.w1 = Widget(10); //Allocate some memory
auto b = a; // this(this) called for
b.w
assert(a.w1.array ~is b.w1.array); // Pass
Widget3 c;
c.w2.w1 = Widget(20);
auto d = c; // this(this) for
d.w2.w1
assert(c.w.2.w.1.array !is d.w2.w1.array); //pass
}
[/code]
[/quote]
Good catch on this(this) - it is documented well. But I think the
questionable part is on assignment, not copy construction via
postblit. For assignment the postblit *is* being called and the
language spec (not TDPL) glosses over that. Also, not mentioned
in TDPL is what happens if you do implement your own opAssign. I
think some of the magic goes away if I'm not mistaken (i.e. those
well-crafted postblits will not be called). I think this should
be documented as well.
Thanks
Dan