View mode: basic / threaded / horizontal-split · Log in · Help
October 18, 2012
Const ref and rvalues again...
Hello,

I realize that this has been discussed before, but so far there 
is no solution and this really needs to be a high priority:

We need a way for a function to declare that it doesn't want it's 
argument to be copied, but it also doesn't care whether the 
argument is an rvalue or an lvalue.

The C++ way of doing this would be to declare the argument as a 
const &. Apparently it is not desired that we do the same thing 
for const ref.

Currently, if you want that behavior, you have to write 2^n 
permutations of your function, with n being the number of 
arguments that the function takes.

Here's my attempt at passing a struct to a function that takes 
three arguments without the struct being copied:

int copyCounter = 0;
struct CopyCounter
{
    this(this) { ++copyCounter; }
}
void takeThree(ref in CopyCounter a, ref in CopyCounter b, ref in 
CopyCounter c)
{
    writeln("took three");
}
void takeThree(in CopyCounter a, ref in CopyCounter b, ref in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(ref in CopyCounter a, in CopyCounter b, ref in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(ref in CopyCounter a, ref in CopyCounter b, in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(in CopyCounter a, in CopyCounter b, ref in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(in CopyCounter a, ref in CopyCounter b, in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(ref in CopyCounter a, in CopyCounter b, in 
CopyCounter c)
{
    takeThree(a, b, c);
}
void takeThree(in CopyCounter a, in CopyCounter b, in CopyCounter 
c)
{
    takeThree(a, b, c);
}
static CopyCounter createCopyCounter()
{
    return CopyCounter();
}
void main()
{
    CopyCounter first;
    CopyCounter second;
    CopyCounter third;
    takeThree(first, second, third);
    takeThree(createCopyCounter(), second, createCopCounter());
    assert(copyCounter == 0); // yay, works
}


My propsed solution is this:
- Make functions that take "ref in" arguments also accept rvalues.
- The user can still provide an overload that accepts an rvalue, 
using the "in" keyword, and that one will be preferred over the 
"ref in" version.


What do you think?

Malte
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 03:07:56 UTC, Malte Skarupke 
wrote:
> What do you think?
>
> Malte


I've asked for this before.
http://d.puremagic.com/issues/show_bug.cgi?id=8121


Doesn't seem to be a priority. :(
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, October 18, 2012 05:07:52 Malte Skarupke wrote:
> My propsed solution is this:
> - Make functions that take "ref in" arguments also accept rvalues.

There was some discussion of this, though that seems to me to be basically the 
same as making const ref take rvalues only worse. Certainly, it seems 
inherently broken to me to have a function try and take its arguement by ref 
and then be given an rvalue.

> - The user can still provide an overload that accepts an rvalue,
> using the "in" keyword, and that one will be preferred over the
> "ref in" version.
> 
> 
> What do you think?

in as alias for const scope. scope is generally not applicable to structs (and 
when it is, it's not applied properly - scope currently only works properly 
for delegates), and const just puts us back at const ref again. You appear to 
be suggesting that in do something different here, and I don't think that that 
works.

The most recent, in-depth discussion on this issue can be found here: 
http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com

It wasn't entirely conclusive, but there _was_ some discussion on making ref 
take rvalues. I believe that more research was necessary, and I'm not sure 
where any of it stands now. One of the more promising ideas (IMHO) was to 
simply change it so that auto ref means what it was supposed to mean 
originally - that the programmer wants the argument to be passed efficiently but 
doesn't care whether it's an lvalue or rvalue - but some people screamed about 
that, because they've found the current version of auto ref to be useful (in 
spite of the fact that it doesn't do what it was supposed to do).

Really, I think that this comes down to us needing to figure out how to make it 
so that ref can take lvalues under at least some set of circumstances (which 
seems like a bad idea to me), or we need to come up with a parameter attribute 
which indicates that we don't want the argument copied and don't care if it's 
an lvalue or rvalue (like const& is usually used for in C++ but making it so 
that it's _exactly_ that rather than just being primarily used for that). And 
if we can't use auto ref for that, then we need to come up with a new 
attribute of some kind to do that. However, IIRC Kenji tried to change auto 
ref to do that but ran into issues of some kind. I don't know where it stands 
now.

- Jonathan M Davis
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 03:31:41 UTC, Jonathan M Davis 
wrote:
> On Thursday, October 18, 2012 05:07:52 Malte Skarupke wrote:
>> My propsed solution is this:
>> - Make functions that take "ref in" arguments also accept 
>> rvalues.
>
> There was some discussion of this, though that seems to me to 
> be basically the
> same as making const ref take rvalues only worse.

What would be the problem with const ref taking rvalues?
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, October 18, 2012 06:24:08 jerro wrote:
> What would be the problem with const ref taking rvalues?

Read the thread that I already linked to:

http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com

- Jonathan M Davis
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis 
wrote:
> On Thursday, October 18, 2012 06:24:08 jerro wrote:
>> What would be the problem with const ref taking rvalues?
>
> Read the thread that I already linked to:
>
> http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com
>
> - Jonathan M Davis

I read the thread, and not a single one of the "problematic 
cases" are actually valid C++.

Yes: the faulty MSVC has taught people to do retarded things, or 
be afraid of things that were illegal to begin with (in 
particular, pass an rvalue to a ref, WHICH IS ILLEGAL IN C++), 
such as "increment(5)".

There is actually nothing wrong with creating a temporary when 
something is bound to a const ref, provided the compiler follows 
the rules:

*Only LValues with an EXACT type match may be passed to a 
reference.
*In regards to *const* references, RValues may be copied in a 
temporary, and that temporary bound the the ref.

I'm not saying we particularly *need* this in D (C++ has a "by 
ref" paradigm that makes it more important, but D *rarelly* ever 
passes by const ref).

But if the compiler respects the above two rules (which it 
should), then RValue to const ref is both perfectly doable and 
safe (as safe as refs get anyways).
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 06:11:26 UTC, monarch_dodra wrote:
> On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis 
> wrote:
>> On Thursday, October 18, 2012 06:24:08 jerro wrote:
>>> What would be the problem with const ref taking rvalues?
>>
>> Read the thread that I already linked to:
>>
>> http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com
>>
>> - Jonathan M Davis
>
> I read the thread, and not a single one of the "problematic 
> cases" are actually valid C++.
>
> Yes: the faulty MSVC has taught people to do retarded things, 
> or be afraid of things that were illegal to begin with (in 
> particular, pass an rvalue to a ref, WHICH IS ILLEGAL IN C++), 
> such as "increment(5)".
>
> There is actually nothing wrong with creating a temporary when 
> something is bound to a const ref, provided the compiler 
> follows the rules:
>
> *Only LValues with an EXACT type match may be passed to a 
> reference.
> *In regards to *const* references, RValues may be copied in a 
> temporary, and that temporary bound the the ref.
>
> I'm not saying we particularly *need* this in D (C++ has a "by 
> ref" paradigm that makes it more important, but D *rarelly* 
> ever passes by const ref).
>
> But if the compiler respects the above two rules (which it 
> should), then RValue to const ref is both perfectly doable and 
> safe (as safe as refs get anyways).

By allowing the the C++ semantics the function looses semantic 
information - whether the actual parameter was lvalue or rvalue. 
This semantic info can be used bot for compiler optimizations and 
move semantics. This is the reason C++11 added && references.

General question (might not be relevant to current design of D):
How about leaving the decision to the compiler and let the 
programmer only specify usage intent?
E.g.: (I'm speaking semantics here, not syntax)
void foo(const Type t); // 1. I only read the value
void foo (mutate Type t); // 2. I want to also mutate the actual 
parameter
void foo (move Type t); // 3. I want to move the actual parameter

In case 1 above, the compiler is free to pass lvalues by const& 
and rvalues by value or perhaps optimize above certain size to 
const& too.
In case 2, the compiler passes a ref to lvalue, rvalues are not 
accepted at CT.
If I want move semantics, I can use option 3 which accepts 
rvalues by ref. btw, what's the correct semantics for lvalues 
here?

What do you think?
October 18, 2012
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 06:11:26 UTC, monarch_dodra wrote:
> On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis 
> wrote:
>> On Thursday, October 18, 2012 06:24:08 jerro wrote:
>>> What would be the problem with const ref taking rvalues?
>>
>> Read the thread that I already linked to:
>>
>> http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com
>>
>> - Jonathan M Davis
>
> I read the thread, and not a single one of the "problematic 
> cases" are actually valid C++.
>
> Yes: the faulty MSVC has taught people to do retarded things, 
> or be afraid of things that were illegal to begin with (in 
> particular, pass an rvalue to a ref, WHICH IS ILLEGAL IN C++), 
> such as "increment(5)".
>
> There is actually nothing wrong with creating a temporary when 
> something is bound to a const ref, provided the compiler 
> follows the rules:
>
> *Only LValues with an EXACT type match may be passed to a 
> reference.
> *In regards to *const* references, RValues may be copied in a 
> temporary, and that temporary bound the the ref.
>
> I'm not saying we particularly *need* this in D (C++ has a "by 
> ref" paradigm that makes it more important, but D *rarelly* 
> ever passes by const ref).
>
> But if the compiler respects the above two rules (which it 
> should), then RValue to const ref is both perfectly doable and 
> safe (as safe as refs get anyways).

The problem with binding rvalues to const ref is that you could 
take and store the address of it. That's why I'd recommend using 
"in ref" instead.

@Jonathan: I had already read the linked discussion. There are 
many valid points in there, but also many invalid ones (as 
monarch_dodra has pointed out). But I think all problems in that 
thread should be solved by using "in ref" instead of "const ref" 
because then you'd be sure that the passed-in temporary can not 
escape the current function.

@foobar: I like the idea, but it's probably going to break down 
in many cases. If you have a non-trivial copy constructor you 
want the ability to have complete control over when it gets 
copied and when it doesn't. I just don't trust compilers enough 
to think that they'd always make the same choice that I'd make.
And also about losing semantic information: That's why I proposed 
the second point: Give the user the option to provide a function 
which should be preferred for rvalues. That way you don't lose 
semantic information.
October 19, 2012
Re: Const ref and rvalues again...
> The problem with binding rvalues to const ref is that you could 
> take and store the address of it. That's why I'd recommend 
> using "in ref" instead.

You can also take and store the address of a local variable that 
was passed as a const ref parameter, and accessing it after the 
caller exits will result in undefined behavior too. On the other 
hand,  addresses of both local variables and rvalues will be 
valid at least until the called function returns. Local variables 
and rvalues are equivalent in regard to this problem.
October 19, 2012
Re: Const ref and rvalues again...
On 10/19/2012 01:39 AM, Malte Skarupke wrote:
> On Thursday, 18 October 2012 at 06:11:26 UTC, monarch_dodra wrote:
>> On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis wrote:
>>> On Thursday, October 18, 2012 06:24:08 jerro wrote:
>>>> What would be the problem with const ref taking rvalues?
>>>
>>> Read the thread that I already linked to:
>>>
>>> http://forum.dlang.org/thread/4F84D6DD.5090405@digitalmars.com
>>>
>>> - Jonathan M Davis
>>
>> I read the thread, and not a single one of the "problematic cases" are
>> actually valid C++.
>>
>> Yes: the faulty MSVC has taught people to do retarded things, or be
>> afraid of things that were illegal to begin with (in particular, pass
>> an rvalue to a ref, WHICH IS ILLEGAL IN C++), such as "increment(5)".
>>
>> There is actually nothing wrong with creating a temporary when
>> something is bound to a const ref, provided the compiler follows the
>> rules:
>>
>> *Only LValues with an EXACT type match may be passed to a reference.
>> *In regards to *const* references, RValues may be copied in a
>> temporary, and that temporary bound the the ref.
>>
>> I'm not saying we particularly *need* this in D (C++ has a "by ref"
>> paradigm that makes it more important, but D *rarelly* ever passes by
>> const ref).
>>
>> But if the compiler respects the above two rules (which it should),
>> then RValue to const ref is both perfectly doable and safe (as safe as
>> refs get anyways).
>
> The problem with binding rvalues to const ref is that you could take and
> store the address of it. That's why I'd recommend using "in ref" instead.
>
> @Jonathan: I had already read the linked discussion. There are many
> valid points in there, but also many invalid ones (as monarch_dodra has
> pointed out). But I think all problems in that thread should be solved
> by using "in ref" instead of "const ref" because then you'd be sure that
> the passed-in temporary can not escape the current function.
>
> @foobar: I like the idea, but it's probably going to break down in many
> cases. If you have a non-trivial copy constructor you want the ability
> to have complete control over when it gets copied and when it doesn't. I
> just don't trust compilers enough to think that they'd always make the
> same choice that I'd make.
> And also about losing semantic information: That's why I proposed the
> second point: Give the user the option to provide a function which
> should be preferred for rvalues. That way you don't lose semantic
> information.

Const is different in D and in C++. Relating const and rvalues is 
arbitrary and does not make a lot of sense.

Regarding 'in ref'/'scope ref': What should 'scope' apply to in

void foo(scope ref int* x);
« First   ‹ Prev
1 2 3 4 5
Top | Discussion index | About this forum | D home