In a post-blit world, with no opAssign specified, postblit will call for copy construction AND for assignment, thereby assignment is always
correct.
Once postblit is swapped for a copy-constructor, absence of opAssign
will result in invalid behaviour on assignment.

Indeed, but this was the source of the problem also, because you could
modify immutable fields that way.

Introduction of copy constructor breaks default assignment, it needs to address it somehow. I think my suggestion is the only practical
solution.

Affirmative. The DIP needs to specify how assignment is handled if no opAssign is present but a copy ctor is present. Thanks!

The difference between a copy constructor and opAssign is how the type checking is performed. This leads to situations where a copy constructor is not suitable as an assignment operator. However, if a copy constructor is defined in a way that is correctly type checked both as a constructor and as a normal function, then there is no problem in using the copy constructor for assignments:

struct A
{
    immutable int b;
    int c;
    @implicit this(ref A rhs)
    {
        this.c = rhs.c;
    }
}

struct B
{
    immutable int b;
    int c;
    @implicit this(ref A rhs)
    {
        this.b = rhs.b;
        this.c = rhs.c;
    }
}

void main()
{
    A a, c;
    A b = a;
b = c; // no problem in calling copy constructor, immutable is
                 // not modified
    B d, e;
    B f = d;
f = d; // cannot use copy constructor because it will modify immutable // field B.b; for this situation you need an opAssign to specify
                 // how the assignment is dealt with.
}

The problem with this approach is that some copy constructors will also be used as assignment operators while others will not, but with good error messages it could be handled (error on line `f = d` : opAssign not specified and the copy constructor is not suitable for assignments because it modifies immutable field `b`).

What are your opinions on this?

Reply via email to