On 10/17/24 02:05, Manu wrote:
> On Thu, 17 Oct 2024, 07:36 Timon Gehr via Digitalmars-d, <digitalmars-
> d@puremagic.com <mailto:digitalmars-d@puremagic.com>> wrote:
> ...
>
> I agree with Manu's reasoning why having `this(ref S)` and `this(S)`
> work as "initialization from lvalue" and "initialization from rvalue",
> corresponding to copy and move respectively would be cleaner.
>
> But overall I don't have a strong preference, as dedicated syntax also
> has some benefits. The thing I think is most important is getting the
> semantics right.
>
>
> Special-casing the constructor is just admitting that the overload
> selection mechanics are broken for **all other function calls**... It's
> not a matter of 'preference'; if the overload mechanics work properly
> then special casing the constructor wouldn't even be thinkable or raised
> in conversation. It's a hack; a really dumb hack which just leaves EVERY
> OTHER FUNCTION broken.
>
> The fact you have "no strong preference" surprises me, maybe I've
> misunderstood some way in which this is not a hack that's totally
> broken?
There is a tradeoff. I think a `this(S)` has to call the destructor of
the argument at the end of its scope. This is the right thing to do for
normal functions, but you might expect a move constructor to not call it
as it already destroys it as part of its normal operation. DIP1040 tried
to fix this by _special-casing the constructor_. ;)
With a syntax based on `ref`, it is clear that there will not be a
destructor call.
But upon very trivial investigation we quickly determined that all arguments need to be cleaned up; it avoids complicated special cases and additional attribution. If there's an opportunity for destructor elision, it would be an advanced optimisation. It shouldn't be the basic semantic for simplicity's sake... and when you accept that, any complexity around the design disappears completely.
> Can you explain to me how every other function call isn't broken
> under the special-case-for-move-constructor solution?
Move semantics still needs a separate solution, but this thread is about
move constructors. Move constructors are not needed for move semantics,
they are needed to manually hook moves that involve a transfer of values
between different memory locations.
They're not 'a thing' though, they are just a natural consequence of move semantics. Move construction will work naturally given an rvalue constructor, no special cases, no rules, probably not even one single line of code in the compiler is necessary once move semantics are working generally.
I think this is where it's gotten lost...
Move semantics don't need a "separate solution", they are actually the conversation we're meant to be having.
This talk about move constructors is where it's all gotten lost in the woods; If move semantics exist, then move constructors don't need "a solution" at all, they just work naturally with no further intervention.
I'm pretty sure that confusion is the basis for the madness going on here... people seem to be obsessed with move construction while completely ignoring or overlooking move semantics in general, or somehow thinking it's separate or secondary?
So, to belabour the point... move semantics is the primary concept here; and there should be no "move constructor" as a distinct feature, it's just a natural consequence of move semantics existing. No conversation about move constructors is necessary... this is all just leading to confusion.
Reframe thought experiments in terms of `void f(ref T)`, and `void f(T)`, hopefully that should eliminate confusion. Select the proper overload in that set when calling f(...), and we're done here.
Please, everyone stop talking about "move constructors"... at least until you've understood what move semantics are. Get your head around move semantics, then you will naturally understand how redundant and misleading this entire conversation about move constructors is...
> Overload selection
> has to work, it is basically the meat of this whole thing... there's not
> really anything else to it.
>
> Broken calling semantics for every function other than the constructor
> is not a 'compromise', it baffles me that people would even consider it.
> I mean, you don't 'call' constructors so often, but you do call
> everything else.
>
I am completely with you here.
I know, but once readers understand and accept this, they will also understand that move constructors aren't "a thing", they're just a normal constructor with a rvalue as argument, and calling semantics/overload selection is necessarily the same as any other function.
I think this confusion and noise will all disappear as soon as people understand this.