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

Reply via email to