On Fri, 4 Oct 2024 at 01:51, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
On 10/2/2024 4:17 PM, Manu wrote:
> your __rvalue() is essentially the `T move(ref T)` intrinsic we discussed at
> length; so why not just make the move intrinsic rather than this thing?

My original plan was to do just that:
```
S move(ref S s) => s;
```
would be recognized and replaced with the `__lvalue(s)`. What bothered me about
it was the magic behavior of it, such as what happens with:
```
S move(ref S s, int i) => s;
```
which will behave completely differently, and may be quite surprising to users.
I expect somebody will inevitably set at store on:

```
S move(ref S s) => s;
S move(ref S s, int i) => s;
```
doing the same thing, but they don't, and the user will be baffled and I will
get bug reports and the language will become more complicated is in the ugly way
C++ became.

Okay, fair. I'm convinced.

> 'move' is the operation we seek, and it has
> lifetime related semantics involved with the operation. __rvalue() doesn't feel
> like the right abstraction for that set of semantics; you're gonna find yourself
> wondering where to pin the lifetime semantics in the future...

__rvalue() does nothing more than say its argument is not an lvalue, so it will
not match with a `ref` parameter. Lifetime analysis occurs after overload
resolution, so I don't think it will impact it.

__rvalue() is not a move, it just guides the overload resolution to the move
constructor/assignment. It's a hint.

Okay, so then from this perspective without any obvious place to pin any lifetime tracking semantics, the lifetime of an argument to move will continue after the call to move; which implies (as we discussed at some length) that the callee MAY move the object, and if it does, the callee is responsible for putting it back in an init state so that it is valid when the calling object is destructed at some later time...
This is fine, and we tolerate this arrangement in C++ (probably for the exact same reasons), but it's not quite an optimal solution. Sufficiently capable lifetime tracking could theoretically elide calls to destructors when it knows a move took place, but I can't see a way the calling scope can have any such confidence with __rvalue() as a tool?

I guess this is where Timon's proposal for @move comes in. Incidentally, that proposal seems to be additive to this work though; it could be added later to give the calling scope that information, but it doesn't seem to contradict your current path.

I think I'm satisfied with your direction.
It'd be interesting if you could push a working branch? I've been writing a whole bunch of containers the last few days and I'd like to try it out if it's in a testable state.