Thread overview
How to fix opAssign signature
Nov 02, 2012
Dan
Nov 02, 2012
Ali Çehreli
Nov 07, 2012
Dan
November 02, 2012
The following works, but I want to make opAssign in D take const ref D.
It needs to still print "(dup here)". How can this be done?

Thanks
Dan

----------------
import std.stdio;

struct A {
  char a[];
  this(this) { a = a.dup; writeln("(dup here)"); }
}
struct B { A a; }
struct C { B b; }
struct D {
  C c;
  // How can I make this take const ref D other
  ref D opAssign(ref D other) {
    c = other.c;
    return this;
  }
}

void main() {
  D d, d2;
  d2 = d;
}

November 02, 2012
On 11/02/2012 05:29 AM, Dan wrote:
> The following works, but I want to make opAssign in D take const ref D.
> It needs to still print "(dup here)". How can this be done?
>
> Thanks
> Dan
>
> ----------------
> import std.stdio;
>
> struct A {
> char a[];
> this(this) { a = a.dup; writeln("(dup here)"); }
> }
> struct B { A a; }
> struct C { B b; }
> struct D {
> C c;
> // How can I make this take const ref D other
> ref D opAssign(ref D other) {
> c = other.c;
> return this;
> }

Try the copy-then-swap idiom, which is both exception-safe and efficient:

import std.algorithm;

// ...

    ref D opAssign(D other) {
        swap(c, other.c);
        return this;
    }

There may be corner cases where this is not efficient, but considering that assignment involves two sub-operations (make a copy of the new state and destroy the old state), the above is doing exactly that. (It is the same idiom for strongly exception-safe operator= in C++.)

That has been the observation that led me to understand that by-value is the way to go with struct opAssign. Please let us know whether it has weaknesses. :)

> }
>
> void main() {
> D d, d2;
> d2 = d;
> }
>

Ali
November 07, 2012
On Friday, 2 November 2012 at 15:56:47 UTC, Ali Çehreli wrote:
>
>     ref D opAssign(D other) {
>         swap(c, other.c);
>         return this;
>     }
>
> There may be corner cases where this is not efficient, but considering that assignment involves two sub-operations (make a copy of the new state and destroy the old state), the above is doing exactly that. (It is the same idiom for strongly exception-safe operator= in C++.)
>
> That has been the observation that led me to understand that by-value is the way to go with struct opAssign. Please let us know whether it has weaknesses. :)
>
[snip]
> Ali

Neat trick. But how do you deal with this?
D d1;
const(D) d2;
d1 = d2

As soon as I add an assoc array to A I need to implement an opAssign if I want to be able to assign a const(A) to an A. And I would want to be able to do that for this composition. Note the cast - is that safe?

import std.stdio;
struct B {
  private A _a;
  @property auto a(const ref A other) {
    _a = other;
  }
}

struct A {
  int[1024] i;   /// Very big making pass by value bad choice
  string[string] h;
  auto opAssign(const ref A other) {
    h = cast(typeof(h))other.h.dup;
  }
}

void main() {
  B b;
  A a = { [0], [ "foo" : "bar" ] };
  b.a = a;
}


Thanks
Dan