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

Walter Bright newshound2 at digitalmars.com
Fri Jan 25 11:56:58 UTC 2019

On 1/24/2019 11:53 PM, Nicholas Wilson wrote:
> That the conflation of pass by reference to avoid copying and mutation is not 
> only deliberate but also mitigated by @disable.

The first oddity about @disable is it is attached to the foo(int), not the 
foo(ref int). If I wanted to know if foo(ref int) takes rvalue references, I'd 
have to go looking for the existence of another function. This is one of those 
cases where it's hard to prove a negative, as other functions can be introduced 
by mixins. This is a strong usability negative.

Next, the @disable applies to the entire parameter list. However, overload 
selection is done by looking at each parameter. The DIP says:

"The DIP author responded that ideas to improve this are welcome, but that he 
cannot imagine a use case."

I can guarantee that the use case of more than one reference parameter will come 
up. The workarounds the DIP suggests are simply awful.

Let's look at what C++ does for rvalue references:


The syntax is attached to the parameter declaration of the function it applies 
to, not some other function, and not every parameter:

     int foo(T&& t);  // C++ rvalue ref

There are no weird workarounds, at least for that aspect. There are indeed 
unlikable things about the C++ rules, but the DIP needs to pay more attention to 
how C++ does this, and justify why D differs. Particularly because D will likely 
have to have some mechanism of ABI compatibility with C++ functions that take 
rvalue references.

This is not a small problem.

A further problem is implicit conversions, which the DIP ignores by only talking 
about ints.

     void bar(int);
     void foo(ref int);
     enum short s = 10;
     bar(s); // compiles
     foo(s); // currently fails to compile

Should `s` be promoted to an int temporary, then pass the temporary by 
reference? I can find no guidance in the DIP. What if `s` is a uint (i.e. the 
implicit conversion is a type paint and involves no temporary)?

Here's a discussion of Rust and rvalue references which may offer insight:


> That the DIP applies to statements, not expressions.

The DIP should not invent its own syntax, give no explanation of it, and have 
the reader guess. (It did explain the :=, but not the use of { } and 
statements.) And, even if one did a mental rewrite, the semantics of the 
statement version are simply wrong. (For example, if 'fun' was actually a 
function pointer returned by another function, and that other function threw an 
exception - then the destructor would be run on an uninitialized variable.)

> That the construction order issue is trivially fixable, by specifying the same 
> behaviour as the non ref case modulo ref.

It should never have gotten this far without giving a precise explanation of how 
exception safety is achieved when faced with multiple parameters. In the past 
I've done a lot of work on exception safety, and it isn't trivial once one goes 
beyond trivial cases.

All that criticism aside, I'd like to see rvalue references in D. But the DIP 
needs significant work.

More information about the Digitalmars-d-announce mailing list