Does D really need something like const&?
Steven Schveighoffer
schveiguy at yahoo.com
Fri Mar 1 17:15:20 PST 2013
On Fri, 01 Mar 2013 19:49:54 -0500, Era Scarecrow <rtcvb32 at yahoo.com>
wrote:
> On Friday, 1 March 2013 at 23:46:36 UTC, Steven Schveighoffer wrote:
>> This is the major problem that Andrei had with it (at least as I
>> understand his past statements) -- it conflates const with rvalue
>> references. Sometimes, you want a const ref that does NOT bind to an
>> rvalue.
>
> If I have a medium sized struct that I only intend to read/reference
> from I see no reason not to use 'const ref' for simplicity and speed
> (and avoid postblit hopefully) but when it's an Rvalue I need to make a
> second function either duplicate except signature or forwarding the
> value.
The point is simple:
foo(ref M m)
foo(M m)
An lvalue, yes, we want that to bind to ref.
But an rvalue? I want that to bind to foo(M m), otherwise I would not
have added that method. The by-value version is *more efficient* than the
by-ref version with rvalues, even for large structs.
But what if I ALSO want to say that foo doesn't change m? Well, that's
easy! I just do:
foo(const ref M m)
But this makes rvalues bind to that version too! This is the problem. I
want it to be ref, to avoid copies of a larg struct, and I want it to be
const, for contract purposes, I DIDN'T want it to accept rvalues.
The point is, there is a legitimate reason to mark a parameter const ref
BESIDES wanting to have it bind to rvalues.
>> The one huge problem I've had with lack of rvalue references is with
>> arithmetic operators:
>>
>> struct M
>> {
>> M opAdd(const ref M other) const {...}
>> }
>>
>> M m;
>>
>> auto m2 = (m + m) + m; // ok!
>> auto m3 = m + (m + m); // error!
>>
>> This is crap.
>
> If 'auto ref' gets accepted for non-template functions, it goes away.
> With M as you show, returning ref doesn't work so that example I was
> going to suggest doesn't work.
In my code base, I have actual comments that explain why I have ordered
certain operations the way I did!
But we have more problems than just rvalue references. The compiler
doesn't "see through" structs to know whether something is an lvalue or an
rvalue.
Consider writing your own pointer type:
struct T
{
int *x;
void opUnary(string op)() if (op == "++") {++(*x);}
}
int x;
T foo()
{
return T(&x);
}
void main()
{
auto t = foo;
t++; // ok
foo++; // Error: foo() is not an lvalue
}
That should not be an error, or I should at least be able to tell the
compiler "this is NOT an rvalue, even if it seems like one".
-Steve
More information about the Digitalmars-d
mailing list