September 06, 2019
On Friday, 6 September 2019 at 22:32:55 UTC, Manu wrote:
> S is an rvalue; there are no other references to S. That's the point.

With rvalue ref there is a reference. That's the point of rvalue ref passing rvalue around by reference.

September 06, 2019
On Fri, Sep 6, 2019 at 3:55 PM Suleyman via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Friday, 6 September 2019 at 22:32:55 UTC, Manu wrote:
> > S is an rvalue; there are no other references to S. That's the point.
>
> With rvalue ref there is a reference. That's the point of rvalue ref passing rvalue around by reference.

The whole point is to destroy the source value though, because there's no external reference to it. If you receive an rvalue ref, it's yours to do as you like with it.
September 07, 2019
On Friday, 6 September 2019 at 20:24:24 UTC, Suleyman wrote:
> On Friday, 6 September 2019 at 17:59:11 UTC, kinke wrote:
>> The problem here is the extended lifetime of the by-value parameter. Example:
>>
>> T global;
>>
>> void foo(T param) { /* make `param` own a huge buffer */ }
>>
>> void caller()
>> {
>>     foo(move(global));
>>     // without destructing and resetting to T.init, `param` continues to live
>>     // and keeps the huge buffer alive, until `global` is reassigned or destructed
>> }
>
> I see no problem with that. That is valid behavior with rvalue ref. You're trying to get the benefit of rvalue ref you can't get the full benefit without the draw backs. There is no in middle solution, either pass by ref or call the move constructor.

I never meant to make such a huge breaking change to existing semantics (by-val param possibly not destructed when going out of scope), just to optimize passing moved lvalues to by-value params by only doing an implicit 'half move' (no allocated temporary, no move ctor call, just destruct and then reset to T.init). I'm not sure this 'middle solution' is really feasible either, that's why we are discussing.

Wrt. rvalue ref params and return 'values', maybe we could get away without introducing `@rvalue ref` by changing the current `auto ref` semantics for params (and return 'values') to what you proposed - an l/rvalue ref, i.e., a reference in both cases, just annotated with rvalue-ness, and never a value anymore. Then, your example

> @rvalue ref get(@rvalue ref S arg) { return arg; }
> void foo(@rvalue ref S);

can be expressed as:

```
auto ref get()(auto ref S arg) { return forward(arg); }
void foo()(auto ref S s);
```

In the (unlikely?) case you really only want to be called with an rvalue ref, you could use a template constraint like

```
void foo()(auto ref S s)
  if (__traits(isRvalueRef, s));
```

The semantics of an `auto ref` param would still need to be clarified in the rvalue case - is it seen as an rvalue ref (breaking change!) or as a value? I.e.:

```
void sink(S s);

void seenAsRvalueRef()(auto ref S s)
{
    // considering rvalue case only:
    sink(s); // automatically moved
    sink(s); // automatically moved again (but probably reset to S.init above)
}

void seenAsValue()(auto ref S s)
{
    sink(s); // passed by value, i.e., copy
    sink(forward(s)); // explicitly moved
}
```

I'd prefer the latter value-view, as that's compatible with current semantics.
September 07, 2019
On Saturday, 7 September 2019 at 12:04:49 UTC, kinke wrote:
> Wrt. rvalue ref params and return 'values', maybe we could get away without introducing `@rvalue ref` by changing the current `auto ref` semantics for params (and return 'values') to what you proposed - an l/rvalue ref, i.e., a reference in both cases, just annotated with rvalue-ness, and never a value anymore.
> [...]

In C++ terms:

struct S
{
    S(S&&);            // D: moveThis(ref S);
    S& operator=(S&&); // D: ref S opMoveAssign(ref S);
}

// universal reference:
template <typename T> void foo(T&&);
// D: void foo(T)(auto ref T);

// rvalue reference:
void bar(S&&);
// D: void bar()(auto ref S s) if (__traits(isRvalueRef, s));

move/forward working just like in C++, but intrinsics.
September 07, 2019
On Saturday, 7 September 2019 at 06:03:38 UTC, Manu wrote:
> On Fri, Sep 6, 2019 at 3:55 PM Suleyman via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Friday, 6 September 2019 at 22:32:55 UTC, Manu wrote:
>> > S is an rvalue; there are no other references to S. That's the point.
>>
>> With rvalue ref there is a reference. That's the point of rvalue ref passing rvalue around by reference.
>
> The whole point is to destroy the source value though, because there's no external reference to it. If you receive an rvalue ref, it's yours to do as you like with it.

Yes you can do anything including rendering the object invalid and even without this feature. You don't need this feature because it generally doesn't make sense and you can do without it.

September 07, 2019
On Saturday, 7 September 2019 at 12:04:49 UTC, kinke wrote:
> I never meant to make such a huge breaking change to existing semantics

I thought what you proposed only affected the output of the __move intrinsic. The __move intrinsic doesn't exist in the language yet so there is no existing semantics affected.

September 07, 2019
On Sat, Sep 7, 2019 at 1:30 PM Suleyman via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Saturday, 7 September 2019 at 06:03:38 UTC, Manu wrote:
> > On Fri, Sep 6, 2019 at 3:55 PM Suleyman via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >>
> >> On Friday, 6 September 2019 at 22:32:55 UTC, Manu wrote:
> >> > S is an rvalue; there are no other references to S. That's the point.
> >>
> >> With rvalue ref there is a reference. That's the point of rvalue ref passing rvalue around by reference.
> >
> > The whole point is to destroy the source value though, because there's no external reference to it. If you receive an rvalue ref, it's yours to do as you like with it.
>
> Yes you can do anything including rendering the object invalid and even without this feature. You don't need this feature because it generally doesn't make sense and you can do without it.

I don't know what you mean. It absolutely makes sense, and it's very useful.
September 07, 2019
On Saturday, 7 September 2019 at 20:39:19 UTC, Manu wrote:
> I don't know what you mean. It absolutely makes sense, and it's very useful.

Moving an object doesn't means it for dump it just means change it's memory location, the object is still expected to be fully functional.

September 07, 2019
On Saturday, 7 September 2019 at 12:04:49 UTC, kinke wrote:
> ```
> void foo()(auto ref S s)
>   if (__traits(isRvalueRef, s));
> ```

This is a really just an awkward way of doing `void foo(@rvalue ref S s)`.

> I'd prefer the latter value-view, as that's compatible with current semantics.

At this point you have essentially admitted rvalue ref in the language but you're fighting to keep it hidden from the user as much as possible. I personally don't thing rvalue ref is that much dangerous to be kept away from the programmers hand. Hiding rvalue ref under auto ref is simply discouraging people from using it.

September 07, 2019
On Saturday, 7 September 2019 at 21:09:45 UTC, Suleyman wrote:
> On Saturday, 7 September 2019 at 12:04:49 UTC, kinke wrote:
>> ```
>> void foo()(auto ref S s)
>>   if (__traits(isRvalueRef, s));
>> ```
>
> This is a really just an awkward way of doing `void foo(@rvalue ref S s)`.
>
>> I'd prefer the latter value-view, as that's compatible with current semantics.
>
> At this point you have essentially admitted rvalue ref in the language but you're fighting to keep it hidden from the user as much as possible.

Yes.

> I personally don't thing rvalue ref is that much dangerous to be kept away from the programmers hand. Hiding rvalue ref under auto ref is simply discouraging people from using it.

It's not because of dangerousness or such, but firstly because I think pure rvalue refs (disallowing lvalue args) are used extremely seldomly, and secondly because I want to avoid further syntactic complexity. We have ref, auto ref, scope ref, return ref, now we're discussing @rvalue ref...