Move Constructors - Converting Lvalues to Rvalues

Manu turkeyman at gmail.com
Sat Oct 12 05:56:04 UTC 2024


On Sat, 12 Oct 2024 at 04:20, Jonathan M Davis via Digitalmars-d <
digitalmars-d at puremagic.com> wrote:

> On Monday, September 30, 2024 10:05:16 AM MDT Walter Bright via
> Digitalmars-d
> wrote:
> > I've been implementing move constructors. They are working, at least on
> my
> > test cases so far. They are distinguished by a copy constructor takes its
> > argument by ref, and a move constructor by value:
> >
> > ```
> > struct S
> > {
> >      this(ref S); // copy constructor
> >      this(S);     // move constructor
> > }
> > ```
> > So far, so good. Consider:
> > ```
> > void phone(S s)
> > {
> >      S t = s;  // copy constructor
> > }
> > ```
> > But what if we want to initialize `t` via a move constructor? Somehow,
> `s`
> > has to be converted from an lvalue to an rvalue. This is done via the
> > function rvalue(): ```
>
> Given the we're now looking at having a separate syntax for move
> constructors, I would argue that they should just have to be ref, which
> should eliminate the special cases that you're fighting here.


You really need to re-read the DIP here and understand the design principle
of this whole thing.
This suggestion show us that you either don't understand the DIP, totally
missed the point, or possibly that you fundamentally disagree with the DIP;
and if that's the case, I think you need to present that argument and what
you'd propose instead, rather than talk with respect to implementation of
the DIP with a completely different idea in mind. If you change the
fundamental substance of the DIP, it's a new DIP.

The proposal in the DIP is very simple; struct rvalues are ref too now, so
don't worry about the ref stuff; everything's a ref. The problem to be
solved is, how do we appropriately distinguish an rvalue from an lvalue;
and while we've had a myriad of proposals adding attributes, Walter found
an arrangement where the distinction can be expressed in existing language
in an astonishingly elegant way; recognise that by-value calls (accepts
rvalue) are all actually move opportunities.

void f(ref T) // arg is an lvalue; the syntax says "I have received a
reference to *someone else's* thing"; or put another way, the callee does
NOT own the argument.
void f(T) // arg is an rvalue; this syntax says "I have received this
thing"; the callee owns the argument, and as such, is a valid recipient of
any move operation.
In order to make move operations actually move operations, they need to be
passed by ref (by *rvalue-ref*, so to speak), and that is literally the
entire point of the DIP; the calling convention is adjusted so a by-value
(r-value) parameter is passed by rvalue-ref.

This is what I mean where I say we're talking about "move semantics", but
everyone seems to be fixated on move constructors as if they're an
extraordinarily interesting part of this story.

A move constructor is just an efficient initialisation opportunity, and
it's a small part of the overall story regarding move semantics.

As I see it; the move constructor *must *be an overload; otherwise, surely
you must assume the overload selection rules don't work, and so every
single other function (aside from the move constructor which received a
blessed hack!) will not make a proper selection.
Move semantics ARE proper overload selection, that's the entire meat of
this design. This design *IS* overload selection rules.... to try and work
that problem off to the side would be to have completely missed the point.
If you exclude overload resolution from the picture, then I don't even know
what we're talking about here.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20241012/8b8c9ecd/attachment-0001.htm>


More information about the Digitalmars-d mailing list