DIP 1014

Stanislav Blinov stanislav.blinov at gmail.com
Wed Oct 3 13:56:29 UTC 2018


Shachar, as I don't see a better place of discussing that DIP at 
the moment, I'll pour some observations and thoughts in here if 
you don't mind, will add some comments on GitHub later.
As I see it right now, it's a case of over-engineering of a quite 
simple concept.

1. A new function, called __move_post_blt, will be added to 
DRuntime.

That's unnecessary, if not downright harmful for the language. We 
should strive to remove things from DRuntime, not add to it. The 
core language should deal with type memory, not a .so or dll. And 
it's extraneous, because...

2 and 3. onPostMove and __move_post_blt:

They're unnecessary as well. All that's required is to allow a 
by-value constructor, e.g:

struct S {
     this(S rhs);
}

Any function in D that has a signature of the form

ReturnType foo(Type x);

in C++ would have an equivalent signature of

ReturnType foo(Type&& x); // NOT ReturnType foo(Type x);

because passing by value in D always implies a possible move. The 
'x' in such functions can be safely cannibalized without any 
repercussions, as it is either a temporary on the call site, or, 
which is especially pertaining to the original bugzilla 
discussion, constructed in place via copy elision.

Thus in effect this(S) would be an equivalent of C++'s move 
constructor. We already have a de-facto move-assignment in the 
form of opAssign(S), this(S) would be a natural extension to that.

Note, per above, that it is NOT a copy constructor, although user 
code may want to create a copy *before* calling it, to create the 
temporary.

Such approach reduces added complexity. The only potential 
problem with it would be a need to "special-case" initialization 
from .init, although at the moment, I think even that may be 
unnecessary: this is a hook after all.

Your example from the DIP would become:

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

     @disable this(this);

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

     this(Tracker oldLocation) {
         if( counter is &oldLocation.localCounter )
             counter = &localCounter;
     }

     void increment() {
         (*counter)++;
     }

}

Usage:

auto old = Tracker(true);
// ...
auto new = move(old); // calls Tracker.this(Tracker);

...this avoids any need to inject special postblits into user 
code.

As I see it, in addition to the above, what would be really 
desirable is for move() and emplace() family of calls to become 
compiler intrinsics instead of library constructs. Those at the 
moment are complete poison: being templates they infect user code 
with dependencies on libc (moveEmplace calls memset and memcpy of 
all things) and unnecessary calls to DRuntime (typeid), and they 
of course blow up the amount of generated code in the form of 
template instantiations. That's despite the fact that the 
compiler possesses ALL the necessary knowledge at the time of 
those calls.


More information about the Digitalmars-d mailing list