DIP 1016--ref T accepts r-values--Formal Assessment

Manu turkeyman at gmail.com
Tue Jan 29 06:01:50 UTC 2019

On Mon, Jan 28, 2019 at 12:00 PM Andrei Alexandrescu via
Digitalmars-d-announce <digitalmars-d-announce at puremagic.com> wrote:
> On 1/28/19 1:00 PM, Andrei Alexandrescu wrote:
> > On 1/24/19 3:01 PM, 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. ;)
> >
> > It seems to me that a proposal adding the "@rvalue" attribute in
> > function signatures to each parameter that would accept either an rvalue
> > or an lvalue would be easy to argue.
> >
> > - No exposing existing APIs to wrong uses
> > - The function's writer makes the decision ("I'm fine with this function
> > taking an rvalue")
> > - Appears in the function's documentation
> > - Syntax is light and localized where it belongs
> > - Scales well with number of parameters
> > - Transparent to callers
> >
> > Whether existing keyword combinations ("in", "out", "ref" etc) could be
> > used is a secondary point.
> >
> > The advantage is there's a simple and clear path forward for API
> > definition and use.
> >
> >
> > Andrei
> One more thought.
> The main danger is restricted to a specific conversion: lvalue of type T
> is converted to ref of type U. That way both the caller and the function
> writer believe the value gets updated, when in fact it doesn't. Consider:
> real modf(real x, ref real i);
> Stores integral part in i, returns the fractional part. At this point
> there are two liabilities:
> 1. User passes the wrong parameter type:
> double integral;
> double frac = modf(x, integral);
> // oops, integral is always NaN
> The function silently converts integral from double to real and passes
> the resulting temporary into the function. The temporary is filled and
> lost, leaving user's value unchanged.
> 2. The API gets changed:
> // Fine, let's use double
> real modf(real x, ref double i);
> At this point all correct callers are silently broken - everybody who
> correctly used a real for the integral part now has their call broken
> (real implicitly converts to a double temporary, and the change does not
> propagate to the user's value).
> (If the example looks familiar it may be because of
> https://dlang.org/library/std/math/modf.html.)
> So it seems that the real problem is that the participants wrongly
> believe an lvalue is updated.
> But let's say the caller genuinely doesn't care about the integral part.
> To do so is awkward:
> real unused;
> double frac = modf(x, unused);
> That code isn't any better or less dangerous than:
> double frac = modf(x, double());
> Here the user created willingly created an unnamed temporary of type
> double. Given that there's no doubt the user is not interested in that
> value after the call, the compiler could (in a proposed semantics) allow
> the conversion of the unnamed temporary to ref.
> TL;DR: it could be argued that the only dangerous conversions are lvalue
> -> temp rvalue -> ref, so only disable those. The conversion rvalue ->
> temp rvalue -> ref is not dangerous because the starting value on the
> caller side could not be inspected after the call anyway.

I started reading this post, and I was compelled to reply with this
same response, and then I realised you got there yourself.
I understand your concern, and it has actually been discussed lightly,
but regardless, you'll find that the issue you describe is not
suggested anywhere in this DIP.
This DIP is about passing rvalues to ref... so the issue you describe
passing lvalues to ref does not apply here.
There is no suggestion to change lvalue rules anywhere in this DIP.

More information about the Digitalmars-d-announce mailing list