On Wednesday, 3 October 2018 at 14:07:58 UTC, Shachar Shemesh wrote:

If you read the DIP, you will notice that the *address* in which the old instance resides is quite important...

Allow me to further illustrate with something that can be written in D today:

import std.stdio;

struct Tracker {
    static int globalCounter;
    int localCounter;
    int* counter;

    this (bool local) {
        if (local) counter = &localCounter;
        else counter = &globalCounter;
    }

    // this should be this(Tracker rhs)
    void opAssign(Tracker rhs) {
        // note: taking address of local parameter
// note: LDC will already 'optimize' the move which in the absence // of any move hooks will mess up the address; try with DMD printf("Address of temporary is '%x', counter points to '%x'\n", &rhs, rhs.counter);
        auto d = cast(void*) rhs.counter - cast(void*) &rhs;
printf("... which is '%ld' bytes from the address of temporary.\n", d);
        localCounter = rhs.localCounter;
        counter = rhs.counter;
        if (counter is &rhs.localCounter)
            counter = &localCounter;
    }
}

auto createCounter(bool local = true) {
    Tracker result = Tracker(local);
    return result;
}

auto createCounterNoNRV(bool local = true) {
    return Tracker(local);
}

void main() {

    Tracker stale1, stale2;

    stale1 = createCounter();
    stale2 = createCounter(false);

    Tracker stale3, stale4;

    stale3 = createCounterNoNRV();
    stale4 = createCounterNoNRV(false);
}


If you run the above with DMD, you'll see what I mean about obviating the address. If we get this(typeof(this)) (that is *always* called on move) into the language, the behavior would be set in stone regardless of compiler.

Reply via email to