October 18, 2012
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
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
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
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
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
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
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
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
> 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
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 6 7 8 9 10 11
Top | Discussion index | About this forum | D home