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]

Reply via email to