On Friday, 25 January 2019 at 11:56:58 UTC, Walter Bright wrote:
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:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
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:
https://www.reddit.com/r/rust/comments/3ko5pm/explaining_cs_rvalue_references_from_a_rust/
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.
For future reference, this is what a formal review should be. I'd
also rather your exact words than some summarization of them.