Jump to page: 1 213  
Page
Thread overview
Discussion Thread: DIP 1040--Copying, Moving, and Forwarding--Community Review Round 1
Mar 05, 2021
Mike Parker
Mar 05, 2021
Mike Parker
Mar 05, 2021
Ben Jones
Mar 05, 2021
tsbockman
Mar 05, 2021
Ben Jones
Mar 05, 2021
tsbockman
Mar 05, 2021
H. S. Teoh
Mar 05, 2021
Max Haughton
Mar 06, 2021
deadalnix
Mar 07, 2021
Max Haughton
Mar 05, 2021
tsbockman
Mar 05, 2021
Paul Backus
Mar 06, 2021
tsbockman
Mar 10, 2021
tsbockman
Mar 10, 2021
Max Haughton
Mar 11, 2021
tsbockman
Mar 11, 2021
Imperatorn
Mar 11, 2021
deadalnix
Mar 11, 2021
tsbockman
Mar 11, 2021
Walter Bright
Mar 11, 2021
tsbockman
Mar 11, 2021
Walter Bright
Mar 11, 2021
tsbockman
Mar 12, 2021
tsbockman
Mar 12, 2021
tsbockman
Mar 12, 2021
tsbockman
Mar 12, 2021
Imperatorn
Mar 12, 2021
Max Haughton
Mar 12, 2021
jmh530
Mar 12, 2021
Imperatorn
Mar 12, 2021
Mike Parker
Mar 12, 2021
Imperatorn
Mar 15, 2021
Walter Bright
Mar 15, 2021
tsbockman
Mar 16, 2021
Walter Bright
Mar 16, 2021
tsbockman
Mar 18, 2021
Walter Bright
Mar 18, 2021
tsbockman
Mar 11, 2021
deadalnix
Mar 11, 2021
tsbockman
Mar 11, 2021
tsbockman
Mar 16, 2021
tsbockman
Mar 17, 2021
Q. Schroll
Mar 18, 2021
deadalnix
Mar 19, 2021
Q. Schroll
Mar 11, 2021
Arafel
Mar 11, 2021
Walter Bright
Mar 11, 2021
Walter Bright
Mar 11, 2021
Arafel
Mar 18, 2021
Walter Bright
Mar 11, 2021
deadalnix
Mar 11, 2021
Walter Bright
Mar 12, 2021
deadalnix
Mar 12, 2021
Walter Bright
Mar 12, 2021
deadalnix
Mar 15, 2021
Walter Bright
Mar 16, 2021
deadalnix
Mar 18, 2021
Walter Bright
Mar 18, 2021
Timon Gehr
Mar 18, 2021
deadalnix
Mar 12, 2021
Atila Neves
Mar 12, 2021
tsbockman
Mar 12, 2021
tsbockman
Mar 05, 2021
12345swordy
Mar 08, 2021
RazvanN
Mar 08, 2021
Walter Bright
Mar 08, 2021
RazvanN
Mar 18, 2021
Walter Bright
Mar 08, 2021
deadalnix
Mar 11, 2021
Timon Gehr
Mar 11, 2021
Walter Bright
Mar 12, 2021
deadalnix
Mar 12, 2021
Walter Bright
Mar 12, 2021
deadalnix
Mar 16, 2021
Walter Bright
Mar 16, 2021
deadalnix
Mar 17, 2021
Timon Gehr
Mar 18, 2021
deadalnix
Mar 20, 2021
Walter Bright
Mar 20, 2021
Walter Bright
Mar 20, 2021
H. S. Teoh
Mar 21, 2021
Walter Bright
Mar 21, 2021
deadalnix
Mar 21, 2021
Max Haughton
Mar 21, 2021
deadalnix
Mar 21, 2021
Max Haughton
Mar 22, 2021
deadalnix
Mar 18, 2021
Walter Bright
Mar 18, 2021
Timon Gehr
Mar 20, 2021
Walter Bright
Mar 18, 2021
deadalnix
Mar 12, 2021
Walter Bright
Mar 12, 2021
Timon Gehr
Mar 13, 2021
Max Haughton
Mar 13, 2021
Timon Gehr
Mar 11, 2021
12345swordy
Mar 13, 2021
Walter Bright
Mar 13, 2021
12345swordy
Mar 13, 2021
deadalnix
Mar 14, 2021
12345swordy
Mar 15, 2021
deadalnix
Mar 15, 2021
12345swordy
Mar 15, 2021
12345swordy
Mar 14, 2021
tsbockman
Mar 15, 2021
Walter Bright
Mar 15, 2021
Walter Bright
Mar 15, 2021
12345swordy
Mar 15, 2021
H. S. Teoh
Mar 16, 2021
Walter Bright
Mar 16, 2021
12345swordy
Mar 16, 2021
bachmeier
Mar 16, 2021
H. S. Teoh
Mar 16, 2021
bachmeier
Mar 16, 2021
jmh530
Mar 16, 2021
12345swordy
Mar 12, 2021
tsbockman
Mar 13, 2021
Walter Bright
Mar 13, 2021
deadalnix
Mar 15, 2021
Walter Bright
Mar 17, 2021
vitamin
Mar 17, 2021
Max Haughton
Mar 17, 2021
vitamin
March 05, 2021
This is the discussion thread for the first round of Community Review of DIP 1040, "Copying, Moving, and Forwarding":

https://github.com/dlang/DIPs/blob/a9c553b0dbab1c2983a801b5e89b51c5c33d5180/DIPs/DIP1040.md

The review period will end at 11:59 PM ET on March 19, or when I make a post declaring it complete. Discussion in this thread may continue beyond that point.

Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits, etc.

However, if you have any specific feedback on how to improve the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary that I will write at the end of this review round. I will post a link to that thread immediately following this post. Just be sure to read and understand the Reviewer Guidelines before posting there:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

And my blog post on the difference between the Discussion and Feedback threads:

https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

Please stay on topic here. I will delete posts that are completely off-topic.
March 05, 2021
On Friday, 5 March 2021 at 12:19:54 UTC, Mike Parker wrote:

> However, if you have any specific feedback on how to improve the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary that I will write at the end of this review round. I will post a link to that thread immediately following this post.

The Feedback Thread is here:
https://forum.dlang.org/post/axgfyrxvndxdmffkxvhs@forum.dlang.org
March 05, 2021
On Friday, 5 March 2021 at 12:19:54 UTC, Mike Parker wrote:
> This is the discussion thread for the first round of Community Review of DIP 1040, "Copying, Moving, and Forwarding":
>
> https://github.com/dlang/DIPs/blob/a9c553b0dbab1c2983a801b5e89b51c5c33d5180/DIPs/DIP1040.md

I had a couple of thoughts on how to make the DIP description a bit more accessible (I don't think they change the mechanics at all).

First, I think a possible use of move constructors/move assignment is to support objects with internal pointers like a small sized optimized vector/string.  An example of what a struct like that would look like would be nice.

Second, it might be good to include a discussion of how structs are passed at the ABI level (I assume that's in the spec, but it would be helpful context to just highlight in the DIP).  My understanding is that this proposal doesn't actually change the function ABIs at all (for struct parameters and return values the caller always passes a pointer to the appropriate structs).  At the ABI level, for the move constructor + assignment, the `this` pointer and the pointer to the argument point to distinct structs, and the argument struct will not be used after the function call, correct?

To be clear, the @value attribute is only used for extern(C++) code where we want to force a copy, right?
March 05, 2021
On Friday, 5 March 2021 at 18:35:39 UTC, Ben Jones wrote:
> Second, it might be good to include a discussion of how structs are passed at the ABI level (I assume that's in the spec, but it would be helpful context to just highlight in the DIP).  My understanding is that this proposal doesn't actually change the function ABIs at all (for struct parameters and return values the caller always passes a pointer to the appropriate structs).

Very small structs are often placed in registers when passed by value. This is true both arguments, and return values. For example, when compiled with LDC for AMD64, the function below does not use any stack memory at all - only registers.

struct S {
    int* ptr;
    size_t length;
}

S sliceroo(S s) {
    const bump = int(s.length >= 2);
    return S(s.ptr + bump, s.length - bump);
}

(You can check out the disassembly online with the https://godbolt.org/ Compiler Explorer.)

This optimization would need to be disabled for any type with a move constructor.
March 05, 2021
On Friday, 5 March 2021 at 20:29:01 UTC, tsbockman wrote:
> Very small structs are often placed in registers when passed by value.

> This optimization would need to be disabled for any type with a move constructor.

I'm not sure it would need to be disabled.  I think the only part that would really apply here is who has to call the constructor.

March 05, 2021
On Friday, 5 March 2021 at 21:04:23 UTC, Ben Jones wrote:
> On Friday, 5 March 2021 at 20:29:01 UTC, tsbockman wrote:
>> Very small structs are often placed in registers when passed by value.
>
>> This optimization would need to be disabled for any type with a move constructor.
>
> I'm not sure it would need to be disabled.  I think the only part that would really apply here is who has to call the constructor.

If the main use case for move constructors is to update pointers into a struct instance, how can that work for an instance that no longer has an address in memory at all?

The move constructor itself takes its `this` parameter by reference. How would you even call the move constructor?
March 05, 2021
On Friday, 5 March 2021 at 20:29:01 UTC, tsbockman wrote:
> On Friday, 5 March 2021 at 18:35:39 UTC, Ben Jones wrote:
>> Second, it might be good to include a discussion of how structs are passed at the ABI level (I assume that's in the spec, but it would be helpful context to just highlight in the DIP).  My understanding is that this proposal doesn't actually change the function ABIs at all (for struct parameters and return values the caller always passes a pointer to the appropriate structs).
>
> Very small structs are often placed in registers when passed by value. This is true both arguments, and return values. For example, when compiled with LDC for AMD64, the function below does not use any stack memory at all - only registers.
>
> struct S {
>     int* ptr;
>     size_t length;
> }
>
> S sliceroo(S s) {
>     const bump = int(s.length >= 2);
>     return S(s.ptr + bump, s.length - bump);
> }
>
> (You can check out the disassembly online with the https://godbolt.org/ Compiler Explorer.)
>
> This optimization would need to be disabled for any type with a move constructor.

This is true, however it's worth saying that typically the reason for having move semantics isn't so much performance (for small objects) but managing the lifetime of the struct properly. In this case for move semantics to be useful S would probably have a destructor, which prevents passing in registers anyway.
March 05, 2021
On Fri, Mar 05, 2021 at 09:29:26PM +0000, tsbockman via Digitalmars-d wrote:
> On Friday, 5 March 2021 at 21:04:23 UTC, Ben Jones wrote:
> > On Friday, 5 March 2021 at 20:29:01 UTC, tsbockman wrote:
> > > Very small structs are often placed in registers when passed by value.
> > 
> > > This optimization would need to be disabled for any type with a move constructor.
> > 
> > I'm not sure it would need to be disabled.  I think the only part that would really apply here is who has to call the constructor.
> 
> If the main use case for move constructors is to update pointers into a struct instance, how can that work for an instance that no longer has an address in memory at all?
> 
> The move constructor itself takes its `this` parameter by reference. How would you even call the move constructor?

I think this is confusing semantics with implementation details.

An optimizing compiler may decide to keep the struct inside registers but that doesn't mean it can't also allocate the struct on the stack, the location of which will serve as the address of the struct. As long as the registers are written back to the stack at the point where a pointer might be dereferenced, that's good enough.  And if the pointer is never actually dereferenced, then the whole thing could be elided completely and the struct will exist only in registers.

It's entirely possible that a struct that keeps a pointer to itself with a move ctor that updates the pointer may never actually call the move ctor (e.g., it's used only as a local variable with no escaping references); an optimizing compiler can deduce that no address is actually taken of the struct so it can be held completely in registers. Or there may be some calls to the move ctor implied by the original text of the code, but after eliding some dead code it's determined that the updated pointer never gets read, then the optimizer can just elide the whole thing and enregister the struct.

None of this has to do with the semantics of the move ctor specified by the language. The language specifies certain semantics for certain constructs, but the optimizer is free to arbitrarily transform the program, as long as the *overall* semantics do not change. (Case in point: programs that always produce the same output are sometimes optimized into an empty main() by LDC, because none of the implied complex semantics actually matter as far as actual output is concerned. However, this is not in the purview of the language spec.)


T

-- 
Customer support: the art of getting your clients to pay for your own incompetence.
March 05, 2021
On Friday, 5 March 2021 at 12:19:54 UTC, Mike Parker wrote:
> This is the discussion thread for the first round of Community Review of DIP 1040, "Copying, Moving, and Forwarding":

From the DIP:
> A Move Constructor for struct S is declared as:
>     this(S s) { ... }
> A Move Assignment Operator for struct S is declared as:
>     void opAssign(S s) { ... }

Is the parameter to these methods really pass-by-value?

If so, why??? Making a copy during every move seems unnecessary, and very inefficient. Moreover, for types that define a copy constructor, it could reasonably be argued that calling it OR not calling it BOTH violate the principle of least surprise. I expect moves NOT to call the copy constructor, but I expect pass-by-value WILL call it: a contradiction.

If the parameter is, in fact, intended to be pass-by-reference, then I must strenuously object to the chosen syntax. Please do not make this the one-and-only place in the entire language where the pass-by-value syntax secretly means pass-by-reference. The fact that `this(ref typeof(this))` is already taken by copy constructors is NOT a good reason to violate the established semantics of parameter lists in D. Just use a template parameter to distinguish them, or something.
March 05, 2021
On Friday, 5 March 2021 at 23:03:57 UTC, tsbockman wrote:
> On Friday, 5 March 2021 at 12:19:54 UTC, Mike Parker wrote:
>> This is the discussion thread for the first round of Community Review of DIP 1040, "Copying, Moving, and Forwarding":
>
> From the DIP:
>> A Move Constructor for struct S is declared as:
>>     this(S s) { ... }
>> A Move Assignment Operator for struct S is declared as:
>>     void opAssign(S s) { ... }
>
> Is the parameter to these methods really pass-by-value?
>
> If so, why???

1) When you pass an rvalue to a by-value parameter in D, it's moved, not copied.
2) If you have a by-ref overload and a by-value overload for the same function, the ref one is called for lvalues and the by-value one is called for rvalues.

In fact, this is already how you have to write your opAssign if you want to support explicit move-assignment from rvalues of non-copyable types. See for example SumType's opAssign overload [1], and the corresponding unit test [2].

[1] https://github.com/dlang/phobos/blob/51a70ee267026e150b9b5d81a66ad1fe33112623/std/sumtype.d#L629-L640
[2] https://github.com/dlang/phobos/blob/51a70ee267026e150b9b5d81a66ad1fe33112623/std/sumtype.d#L1141-L1167
« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11