January 24, 2019
On Thursday, 24 January 2019 at 20:01:45 UTC, kinke wrote:
> (most args are probably already default-initialized by the callee in the line above the call...)

Should be 'by the callER' of course.
January 24, 2019
On Thursday, 24 January 2019 at 09:04:41 UTC, Nicholas Wilson wrote:
> On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
>> The second problem is the use of := (which the DIP Author defines as representing "the initial construction, and not a copy operation as would be expected if this code were written with an = expression"). This approach shows its deficiencies in the multiple arguments case; if the first constructor throws an exception, all remaining values will be destroyed in the void state as they never have the chance to become initialized.
>
> Although not specified by the DIP, I think this could be easily remedied by saying that the order of construction is the same as if the temporaries were not bound to ref, i.e.
>
> ---
> struct A {~this();} struct B{ ~this();}
> A a();
> B b();
>
> void f(A a, B b);
> void g(ref A a, ref B b);
>
> f(a(),b());  //(1)
> g(a(),b()); //(2)
> ---
>
> and a() or b() may throw (and are pure), that (1) and (2) exhibit the same exception/destructor semantics.

Describing this stuff in detail (rewritten expression?!), isn't trivial and requires knowledge about how calls and construction/destruction of argument expressions works.
E.g., the f() call in the code above is lowered to (-vcg-ast):

(bool __gate = false;) , ((A __pfx = a();)) , ((B __pfy = b();)) , __gate = true , f(__pfx, __pfy);

Here, (only seemingly unused) temporary `__gate` is used to control the destruction of temporaries with dtors (here just the `__pfx` arg, as `__pfy` is a special case [no potentially throwing later argument expressions...]) at the caller side (false => destruct; true => skip destruction, as it has been moved successfully to the callee, which destructed it). The dtor expressions of these temporaries (e.g., `__gate || __pfx.~this()` for `__pfx`) aren't visible with `-vg-ast`.

With this DIP, *all* rvalues passed by ref must be lowered to temporaries. In case they require destruction, the only difference wrt. the by-value case is that they are *always* destructed by the caller (after the call, or if an exception is thrown while they are in scope), i.e., their destruction isn't controlled by `__gate`.
January 24, 2019
On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
>>fun(10)
>> ==>
>> {
>>  T __temp0 = void;
>>  fun(__temp0 := 10);
>> }
> The first problem the Language Maintainers identified with this approach is that the rewrite is from an expression to a statement, rendering it invalid.
> The expression should be rewritten as an expression to clarify how it behaves in larger expressions.

Couldn't that just be rewritten as something like

fun(tuple(10).expand);

?

January 24, 2019
On Thursday, 24 January 2019 at 09:24:19 UTC, Nicholas Wilson wrote:
> On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
>> Walter and Andrei have declined to accept DIP 1016, "ref T accepts r-values", on the grounds that it has two fundamental flaws that would open holes in the language. They are not opposed to the feature in principle and suggested that a proposal that closes those holes and covers all the bases will have a higher chance of getting accepted.
>>
>> You can read a summary of the Formal Assessment at the bottom of the document:
>>
>> https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1016.md
>
>> void atomicIncrement(ref shared long x);
>> atomicIncrement(myInt);
>
> Raises a good point, not covered by @disable where the intent is to modify it and modifying a temporary is wrong. `out ref` perhaps?

Why isn't it covered by @disable ?
January 24, 2019
On Thursday, 24 January 2019 at 20:01:45 UTC, kinke wrote:
> On Thursday, 24 January 2019 at 09:49:14 UTC, Manu wrote:
>> We discussed and concluded that one mechanism to mitigate this issue
>> was already readily available, and it's just that 'out' gains a much
>> greater sense of identity (which is actually a positive side-effect if
>> you ask me!).
>> You have a stronger motivation to use 'out' appropriately, because it
>> can issue compile errors if you accidentally supply an rvalue.
>
> `out` with current semantics cannot be used as drop-in replacement for shared in-/output ref params, as `out` params are default-initialized on entry. Ignoring backwards compatibility for a second, I think getting rid of that would actually be beneficial (most args are probably already default-initialized by the callee in the line above the call...) - and I'd prefer an explicitly required `out` at the call site (C# style), to make the side effect clearly visible.
>
> I'd have otherwise proposed a `@noRVal` param UDA, but redefining `out` is too tempting indeed. ;)

Yah I'd like this approach way better and it could be an error if the function didn't assign the variable a value instead. Rather than just default initializing it.

void test(out int value) {
    // error: value must be assigned a value
}

In the event the value passed isn't initialized. Can be dangerous if it is a struct with a destructor though. If they void initialized it, but I guess that's a problem with the current implementation as well.
January 24, 2019
On Thursday, 24 January 2019 at 21:57:57 UTC, Rubn wrote:
> it could be an error if the function didn't assign the variable a value instead

I don't like that, conditional mutations like this should work too:

void conditionalIncrement(bool condition, out long value) {
  if (condition)
    ++value;
}

conditionalIncrement(true, 10); // not allowed, rvalue

long value = 10;
conditionalIncrement(true, out value); // fine
January 24, 2019
On Thu, Jan 24, 2019 at 12:05 PM kinke via Digitalmars-d-announce <digitalmars-d-announce@puremagic.com> wrote:
>
> On Thursday, 24 January 2019 at 09:49:14 UTC, Manu wrote:
> > We discussed and concluded that one mechanism to mitigate this
> > issue
> > was already readily available, and it's just that 'out' gains a
> > much
> > greater sense of identity (which is actually a positive
> > side-effect if
> > you ask me!).
> > You have a stronger motivation to use 'out' appropriately,
> > because it
> > can issue compile errors if you accidentally supply an rvalue.
>
> `out` with current semantics cannot be used as drop-in replacement for shared in-/output ref params, as `out` params are default-initialized on entry.

Shared in/out functions are very rare by contrast to out parameters.

> Ignoring backwards compatibility
> for a second, I think getting rid of that would actually be
> beneficial (most args are probably already default-initialized by
> the callee in the line above the call...) - and I'd prefer an
> explicitly required `out` at the call site (C# style), to make
> the side effect clearly visible.
>
> I'd have otherwise proposed a `@noRVal` param UDA, but redefining `out` is too tempting indeed. ;)

Maybe... but there are satisfying options for basically any case we could imagine; and worst case, use a pointer rather than ref. Adding stuff like @norval feels heavy-handed, and I personally judge this issue as being severe enough to warrant that baggage.

What are some legit cases where, assuming a world where we want to avoid naked ref in cases where we want to receive compile errors when users pass rvalues, aren't satisfied by other options?
January 24, 2019
On Thursday, 24 January 2019 at 21:03:29 UTC, kinke wrote:
> Describing this stuff in detail (rewritten expression?!), isn't trivial and requires knowledge about how calls and construction/destruction of argument expressions works.
> E.g., the f() call in the code above is lowered to (-vcg-ast):
>
> (bool __gate = false;) , ((A __pfx = a();)) , ((B __pfy = b();)) , __gate = true , f(__pfx, __pfy);
>
> Here, (only seemingly unused) temporary `__gate` is used to control the destruction of temporaries with dtors (here just the `__pfx` arg, as `__pfy` is a special case [no potentially throwing later argument expressions...]) at the caller side (false => destruct; true => skip destruction, as it has been moved successfully to the callee, which destructed it). The dtor expressions of these temporaries (e.g., `__gate || __pfx.~this()` for `__pfx`) aren't visible with `-vg-ast`.
>
> With this DIP, *all* rvalues passed by ref must be lowered to temporaries. In case they require destruction, the only difference wrt. the by-value case is that they are *always* destructed by the caller (after the call, or if an exception is thrown while they are in scope), i.e., their destruction isn't controlled by `__gate`.

Exactly, doing something that could result in a different outcome would be a disaster.

January 24, 2019
On Thu, Jan 24, 2019 at 1:05 PM kinke via Digitalmars-d-announce <digitalmars-d-announce@puremagic.com> wrote:
>
> On Thursday, 24 January 2019 at 09:04:41 UTC, Nicholas Wilson wrote:
> > On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
> >> The second problem is the use of := (which the DIP Author defines as representing "the initial construction, and not a copy operation as would be expected if this code were written with an = expression"). This approach shows its deficiencies in the multiple arguments case; if the first constructor throws an exception, all remaining values will be destroyed in the void state as they never have the chance to become initialized.
> >
> > Although not specified by the DIP, I think this could be easily remedied by saying that the order of construction is the same as if the temporaries were not bound to ref, i.e.
> >
> > ---
> > struct A {~this();} struct B{ ~this();}
> > A a();
> > B b();
> >
> > void f(A a, B b);
> > void g(ref A a, ref B b);
> >
> > f(a(),b());  //(1)
> > g(a(),b()); //(2)
> > ---
> >
> > and a() or b() may throw (and are pure), that (1) and (2)
> > exhibit the same exception/destructor semantics.
>
> Describing this stuff in detail (rewritten expression?!), isn't trivial and requires knowledge about how calls and construction/destruction of argument expressions works.

Sure, it's not 'trivial', but it is 'simple' in that it's isolated,
and it only affects the part of the DIP that defines the rewrite
semantic. It doesn't lead to "practically a completely differnet DIP"
as was suggested.
Changing the detail of the rewrite such that it has the proper effect
required by the surrounding text and handles exceptions correctly can
probably be done in such a way that not a single line of text requires
any changes.
January 24, 2019
On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
> Walter and Andrei have declined to accept DIP 1016, "ref T accepts r-values", on the grounds that it has two fundamental flaws that would open holes in the language. They are not opposed to the feature in principle and suggested that a proposal that closes those holes and covers all the bases will have a higher chance of getting accepted.
>
> You can read a summary of the Formal Assessment at the bottom of the document:
>
> https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1016.md

Welp, one of the features of the implicit convertion dip that I am going to write depend on this, and it is quite disapointed to see that it is rejected without giving manu a chance for clarification and providing a solution without restarting the dip process again.