October 02, 2018
On Tue, Oct 2, 2018 at 2:40 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 10/2/2018 2:17 AM, Walter Bright wrote:
> > 1. Don't allow moving of C++ structs
> > 2. Add a struct attribute that means "not moveable"
> > 3. DIP 1014, which is add a __move_post_blit() function (most complex solution)
> > 4. Use copy/destruct for C++ structs that have copy constructors (this is the
> > old C++ solution, and is less efficient than the move constructor)
>
> The postblit solution can also work today,
>
> https://issues.dlang.org/show_bug.cgi?id=17448#c37
>
> as the DMD compiler doesn't actually move structs.

Sorry... what?! DMD doesn't move? O_O
We've been talking endlessly about move semantics for like, 10 years...
Do the other compilers move?

I don't understand... I've missed something.

>  So you're OK for the time
> being until DMD does, or a copying garbage collector is implemented.

Ummm...
October 02, 2018
On 10/2/18 1:51 PM, Manu wrote:
> But dangling pointer is an instant crash/memory corruption... it's a
> pretty bad 'bug'.

Yeah doesn't sound very brilliant. I think such a workaround wouldn't fare well. To keep momentum while we mull over a solution to this I suggest you look at porting other data structures.
October 02, 2018
On Tuesday, October 2, 2018 11:54:57 AM MDT Manu via Digitalmars-d wrote:
> On Tue, Oct 2, 2018 at 2:40 AM Walter Bright via Digitalmars-d
>
> <digitalmars-d@puremagic.com> wrote:
> > On 10/2/2018 2:17 AM, Walter Bright wrote:
> > > 1. Don't allow moving of C++ structs
> > > 2. Add a struct attribute that means "not moveable"
> > > 3. DIP 1014, which is add a __move_post_blit() function (most complex
> > > solution) 4. Use copy/destruct for C++ structs that have copy
> > > constructors (this is the old C++ solution, and is less efficient
> > > than the move constructor)>
> > The postblit solution can also work today,
> >
> > https://issues.dlang.org/show_bug.cgi?id=17448#c37
> >
> > as the DMD compiler doesn't actually move structs.
>
> Sorry... what?! DMD doesn't move? O_O
> We've been talking endlessly about move semantics for like, 10 years...
> Do the other compilers move?
>
> I don't understand... I've missed something.

Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like

A foo();
void bar(A);

bar(foo());

is supposed to be guaranteed to move and not copy the return value. Maybe it manages to place the return value in a way that doesn't require actually moving it or copying it, but structs being moved was supposed to be a key thing that D could do. Are we currently getting a bunch of copies that we shouldn't be getting because the compiler isn't yet doing moves when it should be? A number of us have been answering questions for years based on what the spec and TDPL say indicating that the compiler moves structs.

And while I'm all for having objects be moveable by default, I confess that I don't understand what the problem is with the opPostMove idea that the DIP is presenting. I don't think that it should be the norm by any means, but it sure seems like it's cleanly solving a major problem with interacting with C++, and it makes it possible to do stuff like have pointers and dynamic arrays refer to a structs internals in a way that we can't @safely do right now (even though occasionally, it really would be useful to be able to do it). And it sure seems like opPostMove fits in cleanly with the current design, though maybe I'm missing something. Either way, without something like it, we're clearly missing some key functionality for a systems language - particularly one that wants to interoperate with C++.

- Jonathan M Davis



October 02, 2018
On Tuesday, 2 October 2018 at 22:30:38 UTC, Jonathan M Davis wrote:
> Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like

Eh, I don't think that moves it, but rather just constructs it in-place for the next call.
October 02, 2018
On 10/2/2018 4:30 PM, Adam D. Ruppe wrote:
> On Tuesday, 2 October 2018 at 22:30:38 UTC, Jonathan M Davis wrote:
>> Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like
> 
> Eh, I don't think that moves it, but rather just constructs it in-place for the next call.

The technical term for that is "copy elision".
October 03, 2018
On Tue, Oct 2, 2018 at 6:15 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 10/2/2018 4:30 PM, Adam D. Ruppe wrote:
> > On Tuesday, 2 October 2018 at 22:30:38 UTC, Jonathan M Davis wrote:
> >> Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like
> >
> > Eh, I don't think that moves it, but rather just constructs it in-place for the next call.
>
> The technical term for that is "copy elision".

Okay, so copy elision is working... but moves otherwise are not? That's still not what we've been peddling all these years. A whole lot of design surface area is dedicated to implicit move semantics... and they don't work? What does it do? postblit unnecessarily?
October 03, 2018
On Wednesday, 3 October 2018 at 08:21:38 UTC, Manu wrote:
> On Tue, Oct 2, 2018 at 6:15 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On 10/2/2018 4:30 PM, Adam D. Ruppe wrote:
>> > On Tuesday, 2 October 2018 at 22:30:38 UTC, Jonathan M Davis wrote:
>> >> Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like
>> >
>> > Eh, I don't think that moves it, but rather just constructs it in-place for the next call.
>>
>> The technical term for that is "copy elision".
>
> Okay, so copy elision is working... but moves otherwise are not? That's still not what we've been peddling all these years. A whole lot of design surface area is dedicated to implicit move semantics... and they don't work? What does it do? postblit unnecessarily?

The impression is that you are complaining about the continuous lack of "things" based on an incomplete knowledge of how D works in detail ... tragically you invoke low-level features, and you do not know the question.

The fact that in D the structures to date are not moved, is known for years ... take advantage of this fact, and move on.

Work on an implementation that works, AFTER profile it, and possibly complain about performance.
October 03, 2018
On 03/10/18 04:10, Walter Bright wrote:
> On 10/2/2018 4:30 PM, Adam D. Ruppe wrote:
>> On Tuesday, 2 October 2018 at 22:30:38 UTC, Jonathan M Davis wrote:
>>> Yeah. IIRC, it was supposed to be _guaranteed_ that the compiler moved structs in a number of situations - e.g. when the return value was an rvalue. Something like
>>
>> Eh, I don't think that moves it, but rather just constructs it in-place for the next call.
> 
> The technical term for that is "copy elision".

I'm not sure I follow.

First of all, you cannot elide the copy if there is more than one potential local variable you are returning, ala:

A someFunc() {
  A a, b;
  manipulate(a); manipulate(b);

  if( someRandomCondition )
    return a;

  return b;
}

What happens then?

What happens if A has @disable this(this)?

What happens if we explicitly call std.algorithm.move?

Shachar
October 03, 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.
October 03, 2018
On Wednesday, 3 October 2018 at 13:56:29 UTC, Stanislav Blinov wrote:

Aendment, this should of course be:

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