September 05, 2019
On Thursday, 5 September 2019 at 19:38:57 UTC, Suleyman wrote:
> The whole program only calls the destructor for the lvalue, and only once. You need a competitive alternative.

Sry, I haven't focused on that - yes, rvalue refs would be even faster because of elided destruction + T.init reset. For hard-core guys wanting to optimize that away, I'd suggest to just use a regular ref in the function signature and enable `-preview=rvaluerefparam`. A regular ref (combined with either pragma(mangle) tricks or some UDA for C++ mangling) could also be used to represent C++ functions with rvalue refs.
September 05, 2019
On Thu, Sep 5, 2019 at 2:40 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 5 September 2019 at 19:38:57 UTC, Suleyman wrote:
> > The whole program only calls the destructor for the lvalue, and only once. You need a competitive alternative.
>
> Sry, I haven't focused on that - yes, rvalue refs would be even faster because of elided destruction + T.init reset. For hard-core guys wanting to optimize that away, I'd suggest to just use a regular ref in the function signature and enable `-preview=rvaluerefparam`. A regular ref (combined with either pragma(mangle) tricks or some UDA for C++ mangling) could also be used to represent C++ functions with rvalue refs.

Please no. This is a terrible series of sentences >_< `-preview=rvaluerefparam` naturally interacts benefitially with the proposed `@rvalue` attribute. Don't mess with that.
September 05, 2019
On Thursday, 5 September 2019 at 21:31:59 UTC, Manu wrote:
> We lose by-val calling semantics, which are more efficient for small
> struct's (most things), and certain classes of wide-registers in
> various architectures (impossible to codify the proper rules in the
> language).

No, I've explicitly stated that this obviously only affects non-PODs and large PODs. On Win64, `large` is already anything > 8 bytes. Of course we don't want to pass an int by ref.

> You talk about C++ rval references as if they're complex, but they're
> really not.

For people with C++ background they probably aren't. I doubt it'll increase the interest in D from Java/C#/JavaScript people.
[And a great design IMO doesn't include `T&&` meaning different things for a templated function and a regular function, but that's off-topic.]
September 05, 2019
On Thursday, 5 September 2019 at 21:45:10 UTC, Manu wrote:
> On Thu, Sep 5, 2019 at 2:40 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Thursday, 5 September 2019 at 19:38:57 UTC, Suleyman wrote:
>> > The whole program only calls the destructor for the lvalue, and only once. You need a competitive alternative.
>>
>> Sry, I haven't focused on that - yes, rvalue refs would be even faster because of elided destruction + T.init reset. For hard-core guys wanting to optimize that away, I'd suggest to just use a regular ref in the function signature and enable `-preview=rvaluerefparam`. A regular ref (combined with either pragma(mangle) tricks or some UDA for C++ mangling) could also be used to represent C++ functions with rvalue refs.
>
> Please no. This is a terrible series of sentences >_< `-preview=rvaluerefparam` naturally interacts benefitially with the proposed `@rvalue` attribute. Don't mess with that.

Care to elaborate? Suleyman's example can be slightly adapted to this:

void foo(ref S value, int n = 0)
{
    if (n > 32)
        return;

    foo(value, n + 1);
}

With `-preview=rvaluerefparam`, we can feed it with an rvalue too, and get exactly the same behavior as Suleyman's original version, without `@rvalue ref` and the need to move the `value` parameter for the recursive call.
September 05, 2019
On Thu, Sep 5, 2019 at 2:55 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 5 September 2019 at 21:31:59 UTC, Manu wrote:
> > We lose by-val calling semantics, which are more efficient for
> > small
> > struct's (most things), and certain classes of wide-registers in
> > various architectures (impossible to codify the proper rules in
> > the
> > language).
>
> No, I've explicitly stated that this obviously only affects non-PODs and large PODs. On Win64, `large` is already anything > 8 bytes. Of course we don't want to pass an int by ref.

You dismissed the second half of my sentence.

> > You talk about C++ rval references as if they're complex, but
> > they're
> > really not.
>
> For people with C++ background they probably aren't. I doubt it'll increase the interest in D from Java/C#/JavaScript people.

You don't need to use this. `this(T byVal)` is a valid move
constructor if you don't care for the complexity.
But in the event you DO want or need this, then it should be
comprehensive, not compromised.

> [And a great design IMO doesn't include `T&&` meaning different things for a templated function and a regular function, but that's off-topic.]

We have `auto ref`, and I expect that would express that case in a more clear way.
September 05, 2019
On Thu, Sep 5, 2019 at 3:25 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 5 September 2019 at 21:45:10 UTC, Manu wrote:
> > On Thu, Sep 5, 2019 at 2:40 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >>
> >> On Thursday, 5 September 2019 at 19:38:57 UTC, Suleyman wrote:
> >> > The whole program only calls the destructor for the lvalue, and only once. You need a competitive alternative.
> >>
> >> Sry, I haven't focused on that - yes, rvalue refs would be even faster because of elided destruction + T.init reset. For hard-core guys wanting to optimize that away, I'd suggest to just use a regular ref in the function signature and enable `-preview=rvaluerefparam`. A regular ref (combined with either pragma(mangle) tricks or some UDA for C++ mangling) could also be used to represent C++ functions with rvalue refs.
> >
> > Please no. This is a terrible series of sentences >_< `-preview=rvaluerefparam` naturally interacts benefitially with the proposed `@rvalue` attribute. Don't mess with that.
>
> Care to elaborate?

Without that preview, you can't pass an rvalue temporary to a ref at all, so it's a necessary piece of passing rvalues by references.

> Suleyman's example can be slightly adapted to
> this:
>
> void foo(ref S value, int n = 0)
> {
>      if (n > 32)
>          return;
>
>      foo(value, n + 1);
> }
>
> With `-preview=rvaluerefparam`, we can feed it with an rvalue too, and get exactly the same behavior as Suleyman's original version, without `@rvalue ref` and the need to move the `value` parameter for the recursive call.

If you lose the `@rvalue` attribute, you have no idea that you can
steal the contents of `value`... it's not a move argument, it's just
an lvalue argument by ref.
Inside that function, you must copy, because you can't know what you received.
September 05, 2019
On Thursday, 5 September 2019 at 22:31:41 UTC, Manu wrote:
> If you lose the `@rvalue` attribute, you have no idea that you can
> steal the contents of `value`... it's not a move argument, it's just
> an lvalue argument by ref.
> Inside that function, you must copy, because you can't know what you received.

+1

I didn't realize this until I pondered on Exil's argument. Then I realized why the "-preview=..." feature doesn't cover this case. Essentially `ref` doesn't preserve move information i.e. it doesn't tell you whether the source was an lvalue or an rvalue converted to a temporary. Hence you can't just move or `forward` at the bottom of the chain.

September 05, 2019
On Thursday, 5 September 2019 at 22:28:44 UTC, Manu wrote:
> On Thu, Sep 5, 2019 at 2:55 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Thursday, 5 September 2019 at 21:31:59 UTC, Manu wrote:
>> > We lose by-val calling semantics, which are more efficient for
>> > small
>> > struct's (most things), and certain classes of wide-registers in
>> > various architectures (impossible to codify the proper rules in
>> > the
>> > language).
>>
>> No, I've explicitly stated that this obviously only affects non-PODs and large PODs. On Win64, `large` is already anything
>> > 8 bytes. Of course we don't want to pass an int by ref.
>
> You dismissed the second half of my sentence.

Didn't seem relevant, as these are all ABI details, and I am aware of this. My generalization wrt. > 8 bytes on Win64 wasn't totally accurate; vectors > 8 bytes are indeed passed in a vector register. [I have implemented this for LDC - still not fully 100% __vectorcall compatible.]

> We have `auto ref`, and I expect that would express that case in a more clear way.

Yes, definitely better. Brings me to this further refinement of my sketch, staying with Suleyman's recursive function:

void foo()(auto ref S value, int n = 0)
{
    if (n > 32)
        return;

    // forwarding `auto ref` params in the value case could be optimized to
    // 'just forward the [rvalue] ref, don't destruct and reset to T.init afterwards'
    foo(forward(value), n + 1); // still calls the value version of foo
}

void main()
{
    S lvalue;
    foo(move(lvalue)); // pass rvalue directly by ref, then destruct and reset to S.init
}

=> 2 destructions, 1 reset to S.init.
September 06, 2019
On Thursday, 5 September 2019 at 22:57:27 UTC, kinke wrote:
> [...]

Seems workable. It only affects the case of moving an lvalue to an value parameter. But here are my observations:

1. `move` should always do what `forward` did in your example. It shouldn't touch the lvalue, for simply removing a call to the move constructor, because T.init is not always considered a valid state and resetting to T.init is a "move" operation but an uncontrolled one which leaves the object in an invalid state. Which why making __move behave just like rvalue ref is more sensible like your first attempt did. Ex:

```
    S lvalue;
    lvalue.i = 1;
    foo(__move(lvalue));
    assert(lvalue.i == ??); // could be still 1 if wasn't consumed inside foo. this is valid behavior with rvalue ref.
```

This behavior is better than swapping lvalue with T.init.

2. What you have proposed so far only replaces rvalue ref parameters. You haven't tackled rvalue ref returns. What do you propose as an alternative. Ex:

```
    @rvalue ref get(@rvalue ref S arg) { return arg; } // receives pointer and returns it
    void foo(@rvalue ref S);

    S lvalue;
    foo(get(lvalue)); // no copy or move happens only pointers being passed
```

What is your alternative for this.
September 06, 2019
On Thu, Sep 5, 2019 at 4:00 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 5 September 2019 at 22:28:44 UTC, Manu wrote:
> > On Thu, Sep 5, 2019 at 2:55 PM kinke via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >>
> >> On Thursday, 5 September 2019 at 21:31:59 UTC, Manu wrote:
> >> > We lose by-val calling semantics, which are more efficient
> >> > for
> >> > small
> >> > struct's (most things), and certain classes of
> >> > wide-registers in
> >> > various architectures (impossible to codify the proper rules
> >> > in
> >> > the
> >> > language).
> >>
> >> No, I've explicitly stated that this obviously only affects non-PODs and large PODs. On Win64, `large` is already anything
> >> > 8 bytes. Of course we don't want to pass an int by ref.
> >
> > You dismissed the second half of my sentence.
>
> Didn't seem relevant, as these are all ABI details, and I am aware of this. My generalization wrt. > 8 bytes on Win64 wasn't totally accurate; vectors > 8 bytes are indeed passed in a vector register. [I have implemented this for LDC - still not fully 100% __vectorcall compatible.]

It's relevant because the calling convention needs to be defined, and
it's volatile with respect to architecture.
I don't think defining a custom ABI this way is a good path. It's just
different problems, and ABI problems are always bad problems.
1 2 3 4 5 6 7 8 9 10 11 12