On Friday, 7 December 2012 at 14:18:50 UTC, Gor Gyolchanyan wrote:
Consider this example:
I enforce value-type semantics by duplicating the arrays on copy, so it should behave like a value type with no indirections (implicitly convert to
immutable).
What do I need to do for this to work?

My approach is to have a general dup function. I call it gdup, for global dup so the name does not conflict with the existing dup. It dup's fields recursively. Feel free to have a look and any suggestions appreciated. Would greatly appreciate if seasoned D developers like (Ali, bearophile, ...) would review - as I use these mixins to simplify development with structs.

https://github.com/patefacio/d-help/tree/master/d-help/opmix
docs at https://github.com/patefacio/d-help/blob/master/doc/canonical.pdf

Since the gdup makes all new deep copies (as dup should) the cast to immutable is safe. For reference structs with aliasing you have to worry about assignment of immutable to mutable and the reverse. Due to transitive immutability, both are disallowed without something special. dup, idup and gdup in general serve that purpose.

As Ali points out, I also don't think you need the opAssign at all in this case - since default opAssign calls postblit (which is nice). To get value semantics just implement postblit. If you add fields you should not need to worry about it.

As others pointed out - you want deep copy on the items in the array for your custom ctor. Since gdup is recursive and does not require the composed structs to have a postblit - it works even on arrays of T where T has aliasing but no postblit.

Thanks,
Dan

import std.stdio;
import std.traits;
import opmix.mix;

struct Array(Type_)
{
public:
  mixin(PostBlit);
  this(Type_[] array...) {
    _array = array.gdup;
  }
private:
  Type_[] _array;
}

unittest
{
  {
    Array!int one = Array!int(1, 2, 3, 4, 5);
    immutable Array!int two = cast(immutable)one.gdup;
    assert(two._array.ptr != one._array.ptr);
    assert(two._array == one._array);
  }

  {
    struct S {
      // look ma' no postblit
      char[] c;
    }
Array!S one = Array!S(S(['d']), S(['o','g']), S(['b','o','y']));
    auto immutable two = cast(immutable)one.gdup;

    // Ensure the copy was deep (i.e. no sharing)
assert(cast(DeepUnqual!(typeof(two._array.ptr)))two._array.ptr !=
           one._array.ptr);
    assert(typesDeepEqual(two, one));
  }

}

Reply via email to