On Fri, 11 Oct 2024, 18:36 Jonathan M Davis via Digitalmars-d, <digitalmars-d@puremagic.com> wrote:
On Friday, October 11, 2024 1:25:53 AM MDT Manu via Digitalmars-d wrote:
> > Aside from whatever Walter's reasoning is, there are existing constructors
> > in the wild which use
> >
> >     this(S)
>
> I had a moment to think on this case you present.
> It's not clear to me how it actually works now; but I think it would be
> interesting to explore that first; because I think the solution for this
> case being reinterpreted as move-constructor is related (and equally
> solved).
>
> This function receives it's arg BY-VALUE; so it can happily accept an
> r-value... but it's not actually clear how this function receives an lvalue
> even in today's language?
> In order for this function to receive an l-value by-value, it must first
> make a copy to supply as the function's argument (but the function is
> allowed to internally mutate its argument)..
>
> ...but isn't *this* said to be the copy constructor?
>
> This already looks like a chicken/egg problem in today's language... how
> does it create a copy of an lvalue to pass the argument to this function
> without calling this function?
> Whatever answer exists that makes this work equally makes the case work
> where this is reinterpreted as a move-constructor.
>
> The only explanation I can imagine is; because this ISN'T actually a copy
> constructor, the compiler determined that it was appropriate to synthesise
> one (which would be to just copy all members), and so an implicit copy
> constructor DOES actually exist beside this constructor, you just didn't
> write it.
> And assuming that's the case, when this becomes reinterpreted as a move
> constructor, the code remains perfectly correct!
>
> I don't see how elevating this declaration to a move-constructor actually
> changes the semantics at all... I don't think it does? I think this
> function ALREADY IS A MOVE CONSTRUCTOR (at least; it's an
> rvalue-constructor, which is the same thing from a semantic perspective);
> it's just working with an inefficient calling convention.
> Move semantics as proposed simply improve this code, no?

No, as far as the language is concerned, it's not a copy constructor, but it
also isn't necessarily a move constructor. In the case that I've described,

I think it actually is a move constructor... can you explain how it compiles and works differently than what I say? 
You'll need to show me that my hypothesis is wrong...


it might work as a move constructor, but there's no guarantee that all
constructors with that signature would.

Yeah no, I think you're just wrong here. It's exactly a move constructor from a semantic perspective. It receives only rvalues, and the argument belongs to the callee, which can do whatever it likes with it.
It's literally a move constructor with a retarded calling convention... unless my hypothesis about how it compiles at all is wrong?


Also, the constructor is question is
likely to be a template, which will then probably not play well with what
Walter is trying to do (e.g. copy constructors can't currently be templated,
because that doesn't work unless copy constructors have a unique syntax,
which they don't). As Razvan explained in this thread, in order for copy
constructors (or move constructors) to be allowed to be templates, they
really need a distinct syntax, otherwise the compiler can't know that they
are in fact copy constructors or move constructors until they're
instantiated, which causes a variety of issues.

They're all copy or move constructor of some flavour; just not the single special case one that the compiler recognises to suppress it's generation of the default one... they can all exist beside each other subject to functioning overload selection rules.

Any constructor that receives any arg by value is a move constructor for all intents and purposes.


Honestly, as a user, I see _zero_ benefit in trying to treat either copy
constructors or move constructors like they're normal constructors.

Uniformity of semantics. Special cases are bad.

They are
treated as special by the compiler in a variety of ways,

In exactly one way that we were both able to identify, are there actually other cases?

and I want them to
be visually distinct so that it's clear that they exist. It would also be
nice if the compiler gave me an error when I screwed up a copy constructor
or move constructor in a way that it wouldn't work as one for whatever
reason (e.g. getting ref wrong by accident). A big part of the problem with
the current copy constructors is that it really isn't easy to see at a
glance which constructors are copy constructors. And the fact that they
can't be templated is a _huge_ problem, particularly with regards to
attributes.

While the syntax =this() isn't necessarily great (personally, I'd probably
just vote for using @move for move constructors and then change it so that
copy constructors should have @copy), I see nothing but problems from not
making copy and move constructors distinct and obvious.

- Jonathan M Davis

Look, I'm not critically opposed to a special case for the special functions names *if we absolutely do need it and that's just not a lower level design error that we're further compounding*... but I'm absolutely not sold and I think it's a mistake to blindly accept it.

But... and as I mentioned in my response to Walter; reading between the lines, it starts to look like the move semantics somehow uniquely apply to the move constructor and not generally, which is completely insufficient. That's not "move semantics", and it suggests that my reading of the DIP left me with the completely wrong impression.

The move semantic described by the dip should apply to every rvalue everywhere; they're all potential move targets.

Especially so for your weird not-a-move-constructor-but-actually-a-move-constructor that receives T by value; it's the exact definition of a move constructor, and it should be the case that concretely proves that it is also the exact proper syntax for the declaration!