Deprecating this(this)

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sun Apr 1 17:08:37 UTC 2018


On 4/1/18 10:59 AM, Nicholas Wilson wrote:
> On Sunday, 1 April 2018 at 14:31:24 UTC, Andrei Alexandrescu wrote:
>> There's a mix of fundamental flaws and bugs. I'll get to the flaws in 
>> a second. About the bugs: people have altered their code in various 
>> ways to work with the bizarre semantics of this(this). Now, if we fix 
>> various bugs in this(this) by virtually redefining it, then we'll 
>> break a lot of code in a lot of ways. To wit, we fixed a small issue 
>> and it already created problems: 
>> https://github.com/dlang/dmd/pull/8032. That didn't contribute to the 
>> decision but is quite illustrative.
>>
>> I found two fundamental flaws with this(this):
>>
>> 1. For immutable objects, typechecking in the presence of successive 
>> modifications of data (first assignment by the compiler, then 
>> modification by the user) is very difficult if not impossible. I don't 
>> know how to do it. The single initialization model (raw/cooked) used 
>> currently in regular immutable constructors works reasonably well and 
>> is robust.
>>
>> 2. For shared objects, the part done by the compiler and the part done 
>> by this(this) should be synchronized together. This makes it 
>> impossible for the user to e.g. define a struct that gets copied 
>> atomically.
>>
> 
> See my other reply: but why is it necessary to consider the blit 
> logically distinct from the postblit w.r.t to program flow observability?
> 
> for 1. consider
> immutable foo = ...;
> immutable bar = foo;
> to be
> immutable foo = ...;
> immutable bar = () {mutable _ = bitcopy(foo); _.__postblit(); return _;}();

Negative. The problem is typechecking postblit itself, not its invocation.

> for 2. you would have to synchronize anyway for shared, it makes no 
> difference.

Negative. Consider:

shared struct Point
{
     private long x, y, z;
     private Mutex mutex;
     ...
}

Task: define the copy primitive of Point so atomically copy x, y, and z 
using mutex. The problem is, the compiler will memcpy the three longs 
non-atomically before the user even gets a crack at intercepting the 
operation.

>> There'd be an additional issue - this(this) is non-templated, which 
>> requires combinatorial additions when qualifiers are present on the 
>> source or destination side.
> 
> (Perhaps this is what you're referring to, but all you have said so far 
> is "this doesn't work and we need to fix it") the post blit is surely 
> like a destructor: there's only one way to do it, irrespective of the 
> attributes, especially of the intermediate is considered mutable until 
> the end of post blit, like static module constructors initialising 
> global immutables.

Negative. Ignoring qualifiers during copying opens holes in the type 
system the size of China. Or at least Australia as it were :o). Consider:

int[] sneaky;
struct A
{
     private int[] innocent;
     this(this)
     {
         sneaky = innocent;
     }
}
void main()
{
     immutable a = A([1, 2, 3]);
     auto b = a;
     sneaky[1] = 42; // oops
     import std.stdio;
     writeln(a.innocent); // ooooops
}

Sadly this (and many similar ones) compiles and runs warning-free on 
today's compiler. We really need to close this loop, like, five years ago.

> I agree that we should fix any type checking bugs that may be present, 
> and that we should strive to not make the same mistake twice, however I 
> wouldn't call either of the above cases a showstopper. You will need to 
> show more of what is broken and why it is broken given the expected 
> breakage.

Such discussions will be indeed present in the DIP.


Andrei


More information about the Digitalmars-d mailing list