February 09, 2016
On Thursday, 4 February 2016 at 02:33:06 UTC, Andrei Alexandrescu wrote:
> Got it, thanks. That's a bug in the implementation, no two ways about it. No copy should occur there, neither theoretically nor practically. Please report it to bugzilla at http://issues.dlang.org. Thanks very much! -- Andrei

Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662


February 09, 2016
On Tuesday, 9 February 2016 at 00:25:33 UTC, Matt Elkins wrote:
> On Thursday, 4 February 2016 at 02:33:06 UTC, Andrei Alexandrescu wrote:
>> Got it, thanks. That's a bug in the implementation, no two ways about it. No copy should occur there, neither theoretically nor practically. Please report it to bugzilla at http://issues.dlang.org. Thanks very much! -- Andrei
>
> Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662

I've replied to issue 15662.

The point of that issue is, an array concatenation or appending may cause the elements' copy.
The copy occurrence is determined by the runtime situation, so compiler needs to reject such the operation for the @disable this(this) elements conservatively.

Kenji Hara
February 09, 2016
On 2/8/16 7:25 PM, Matt Elkins wrote:
> On Thursday, 4 February 2016 at 02:33:06 UTC, Andrei Alexandrescu wrote:
>> Got it, thanks. That's a bug in the implementation, no two ways about
>> it. No copy should occur there, neither theoretically nor practically.
>> Please report it to bugzilla at http://issues.dlang.org. Thanks very
>> much! -- Andrei
>
> Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662

Thx! -- Andrei

February 10, 2016
On Tuesday, 9 February 2016 at 13:45:13 UTC, Hara Kenji wrote:
> On Tuesday, 9 February 2016 at 00:25:33 UTC, Matt Elkins wrote:
>> On Thursday, 4 February 2016 at 02:33:06 UTC, Andrei Alexandrescu wrote:
>>> Got it, thanks. That's a bug in the implementation, no two ways about it. No copy should occur there, neither theoretically nor practically. Please report it to bugzilla at http://issues.dlang.org. Thanks very much! -- Andrei
>>
>> Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662
>
> I've replied to issue 15662.
>
> The point of that issue is, an array concatenation or appending may cause the elements' copy.
> The copy occurrence is determined by the runtime situation, so compiler needs to reject such the operation for the @disable this(this) elements conservatively.
>
> Kenji Hara

I see. Unfortunate. But thanks for the explanation!
February 10, 2016
On Tuesday, 9 February 2016 at 00:25:33 UTC, Matt Elkins wrote:
> Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662

I'll have to reiterate that this is closely related to another bug (or maybe the same thing, just a lot more compact).

https://issues.dlang.org/show_bug.cgi?id=7032

Bug 7032 refers to opAssign being defined (and being ignored) due to the postblit. A simpler test to what effectively is the same problem is just disabling the postblit (and nothing else).

[code]
struct S {
  @disable this(this);
}

S[] s;
s ~= S(); //error, is not copyable because it is annotated with @disable
[/code]


 I currently can't seem to register/reset/login to bugzilla so i can't post this there :( Could be a change with the site since i haven't been there in 2 years...
February 10, 2016
Back on the original topic, Scott Meyers often says "std::move doesn't move." It's more like std::rvalue_cast. C++ uses r-value references in order to be able to rip the guts out of objects and put them into other objects.

D doesn't have a distinct r-value reference type, and postblit is part of the struct types. If you write simply T foo(); and you return some struct T, D already moves the struct out of the function without you having to define any move constructors. That kind of return value optimisation was the original motivation for r-value references, for when C++98 RVO isn't good enough, from my understanding.

The only remaining time you need to avoid copies is when you take something already on the stack, and then put it into some other object, into some collection, etc. That's the other power that std::move affords you. The move functions in std.algorithm should take care of that.

Maybe someone else will correct me on a point or two there, but that's the understanding of move semantics in D that I have had.
February 10, 2016
On Wednesday, 10 February 2016 at 20:42:29 UTC, w0rp wrote:
> Back on the original topic, Scott Meyers often says "std::move doesn't move." It's more like std::rvalue_cast. C++ uses r-value references in order to be able to rip the guts out of objects and put them into other objects.

Well. In C++ "std::move(x)" is just a "static_cast<T&&>(x)" for "T x".

"T&&" references are different from "T&" by acting like T& references when used, but not on overloads. They are primarily for distinguishing between overloads on temporaries in function calls, T&& binds to temporaries. So you use "std::move(x)" to tell the type system that you want it to be cast as a references to a temporary like reference (or rvalue reference).

So that's why constructors with "T&&" are called move constructors (taking stuff from temporaries) and "const T&" are called copy constructors (assuming that the parameter might have a long life on it's own).

> That kind of return value optimisation was the original motivation for r-value references, for when C++98 RVO isn't good enough, from my understanding.

It is for overloading. Why allocate lots of stuff by copying it if you know that the referenced object is about to die anyway? If it is dying we just steal the stuff it is holding.

stack.push(string("hiii")) // we could steal this stuff
string x("hiii")
stack.push(x) // we have to copy this stuff

> Maybe someone else will correct me on a point or two there, but that's the understanding of move semantics in D that I have had.

I don't think D has move semantics... It does copying and clearing... The postblit thing looks like a dirty hack to me.

February 11, 2016
On Wednesday, 10 February 2016 at 20:42:29 UTC, w0rp wrote:
> The only remaining time you need to avoid copies is when you take something already on the stack, and then put it into some other object, into some collection, etc. That's the other power that std::move affords you. The move functions in std.algorithm should take care of that.
>
> Maybe someone else will correct me on a point or two there, but that's the understanding of move semantics in D that I have had.

Maybe this is what you are referring to, but the primary use I get out of move semantics (in general, not language-specific) has little to do with performance-on-copy. It is for handling resources which logically aren't copyable, which have a unique owner at all times and which should be cleaned up as soon as unique owner falls out of scope. This situation occurs a lot for me, and RAII plus move semantics are pretty close to ideal for handling it. Yes, it can be approximated with reference counting, but reference counting has its own downsides.

C++11 definitely supports this use case. I -think- that D does as well, possible compiler issues aside, though I haven't used it as extensively here to be sure yet. It does seem as though one has to be more careful using these semantics in D, because of how easy it is to stuff such an object into a GC-based container and thereby lose the deterministic nature of the cleanup, but that's just more something to be aware of than a true limitation.
February 11, 2016
On Tuesday, 9 February 2016 at 13:45:13 UTC, Hara Kenji wrote:
> On Tuesday, 9 February 2016 at 00:25:33 UTC, Matt Elkins wrote:
>> On Thursday, 4 February 2016 at 02:33:06 UTC, Andrei Alexandrescu wrote:
>>> Got it, thanks. That's a bug in the implementation, no two ways about it. No copy should occur there, neither theoretically nor practically. Please report it to bugzilla at http://issues.dlang.org. Thanks very much! -- Andrei
>>
>> Done (sorry for the delay): https://issues.dlang.org/show_bug.cgi?id=15662
>
> I've replied to issue 15662.
>
> The point of that issue is, an array concatenation or appending may cause the elements' copy.
> The copy occurrence is determined by the runtime situation, so compiler needs to reject such the operation for the @disable this(this) elements conservatively.
>
> Kenji Hara

Actually, I have a follow-up question about this: when you say that an array concatenation may cause the elements' copy, do you mean only the element being appended? Or can elements already in the array be copied? If the latter, isn't it a problem that my workaround for appending non-copyable objects into the array compiles?

My workaround is like this (typing directly without testing):

// Foo has opAssign defined for rvalues, but post-blit and opAssign for lvalues disabled
Foo[] fooArray;
++fooArray.length;
fooArray[$ - 1] = Foo();


February 11, 2016
On Thursday, 11 February 2016 at 00:32:11 UTC, Matt Elkins wrote:
> unique owner falls out of scope. This situation occurs a lot for me, and RAII plus move semantics are pretty close to ideal for handling it. Yes, it can be approximated with reference counting, but reference counting has its own downsides.

C++ unique_ptr is a semantically a reference-counting ptr with a max count of 1.

So, when you are using a shared_ptr, you also use move semantics. Meaning, you can transfer one shared_ptr to another without the overhead which would be a "move", or you can "copy" by increasing the count by one.

> C++11 definitely supports this use case. I -think- that D does as well, possible compiler issues aside, though I haven't used it as extensively here to be sure yet.

In C++ it is a type system issue, and the actual semantics are up to the programmer. In D it is just copy and clear, which does extra work and is less flexible _and_ forces the copying to happen so you cannot escape it. In C++ the type system tells the class what it _may_ do, not what has already happened (which is what D does). In C++ you aren't required to move, you can choose to use a different strategy/semantics.

Like, in C++ you could do:

"take_one_but_not_both(std::move(a),std::move(b))"

That would not work in D.