Re: const ref parameters and r-value references

2014-05-04 Thread via Digitalmars-d-learn

On Friday, 2 May 2014 at 21:29:51 UTC, Mark Isaacson wrote:
Auto ref parameters seem to be just what I need. Thanks! I'd 
still be curious if anyone has additional information regarding 
the rationale at play (I'm spoiled, reading TDPL and having 
each decision explained in text).


I had the impression that your goal was to avoid copying. I 
didn't write it explicitly, but `auto ref` doesn't do that. It 
just allows you to avoid writing the same function twice, once 
with ref, and once without. It is essentially equivalent to this:


void fun(ref const int x) {
// Stuff
}

void fun(const int x) {
// Stuff
}

This means that you will still get a (bit-wise) copy if you pass 
in an r-value. But semantically, this is a move, not a copy, so 
it is potentially cheaper than a copy (if your type has an 
expensive postblit). You can see this from the following little 
test program:


import std.stdio;

struct S {
this(this) {
writefln(postblit %x, this);
}

~this() {
writefln(destructor %x, this);
}
}

void fun()(auto ref const S x) {
writefln(fun: x = %x, x);
}

void main() {
writeln(passing lvalue ...);
S s;
fun(s);
writeln(copying struct ...);
auto x = s;
writeln(passing rvalue ...);
fun(S());
writeln(done);
}

As you can see, no postblit is called when the struct is passed 
by value:


passing lvalue ...
fun: x = 7a8c73b8
copying struct ...
postblit 7a8c73b9
passing rvalue ...
fun: x = 7a8c7370
destructor 7a8c7370
done
destructor 7a8c73b9
destructor 7a8c73b8


Re: const ref parameters and r-value references

2014-05-04 Thread Timon Gehr via Digitalmars-d-learn

On 05/04/2014 12:58 PM, Marc Schütz schue...@gmx.net wrote:


This means that you will still get a (bit-wise) copy if you pass in an
r-value. But semantically, this is a move, not a copy, so it is
potentially cheaper than a copy (if your type has an expensive postblit).


It can be constructed in-place.


Re: const ref parameters and r-value references

2014-05-04 Thread via Digitalmars-d-learn

On Sunday, 4 May 2014 at 11:15:59 UTC, Timon Gehr wrote:

On 05/04/2014 12:58 PM, Marc Schütz schue...@gmx.net wrote:


This means that you will still get a (bit-wise) copy if you 
pass in an

r-value. But semantically, this is a move, not a copy, so it is
potentially cheaper than a copy (if your type has an expensive 
postblit).


It can be constructed in-place.


Doesn't that depend on the ABI?


Re: const ref parameters and r-value references

2014-05-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Fri, 02 May 2014 08:17:06 +
Mark Isaacson via Digitalmars-d-learn
digitalmars-d-learn@puremagic.com wrote:

 I'm in the process of learning/practicing D and I noticed
 something that seems peculiar coming from a C++ background:

 If I compile and run:

 void fun(const ref int x) {
//Stuff
 }

 unittest {
fun(5); //Error! Does not compile
 }

 I get the specified error in my unit test. I understand that the
 cause is that I've attempted to bind ref to an r-value, what's
 curious is that in C++, the compiler realizes that this is a
 non-issue because of 'const' and just 'makes it work'. Is there a
 rationale behind why D does not do this? Is there a way to write
 'fun' such that it avoids copies but still pledges
 const-correctness while also allowing r-values to be passed in?

By design, in D, ref only accepts lvalues. Unlike in C++, constness has no
effect on that. IIRC, the reasons have something to do with being able to tell
whether the argument is indeed an lvalue or not as well as there being
implementation issues with the fact that const T foo in C++ doesn't necessary
have a variable for foo to refer to. I don't think that I've ever entirely
understood the rationale behind it, but Andrei is quite adamant on the matter,
and it's been argued over quite a few times. I don't know whether D's choice
on the matter is right or not, but it's not changing at this point.
Regardless, the problem that it generates is the fact that we don't have a
construct which does what C++'s const T does - i.e. indicate that you want
to accept both lvalues and rvalues without making a copy.

Andrei suggested auto ref to fix this problem, and Walter implemented it, but
he misunderstood what Andrei had meant, so the result was a template-only
solution. If you declare

auto foo(T)(auto ref T bar) {...}

then when you call foo with an lvalue, foo will be instantiated with bar being
a ref T, whereas if foo is called with an rvalue, it will be instintiated with
bar being a T. In either case, no copy will take place. However, it requires
that foo be templated, and it results in a combinatorial explosion of template
instantiations as more auto ref parameters are added, and the function is used
with various combinations of lvalues and rvalues.

The alternative is to declare each overload yourself:

auto foo(ref T bar) {...}
auto foo(T bar) {...}

That doesn't require the function to be templated, and it works for one, maybe
two function parameters, but you have the same combinatorial explosion of
function declarations as you had with template instantiations with auto ref -
except now you're declaring them all explicitly yourself instead of the
compiler generating them for you.

What has been suggested is that we have a way to mark a non-templated function
as accepting both lvalues and rvalues - e.g.

auto foo(NewRefThingy T bar) {...}

and what it would do is make it so that underneath the hood, foo would
actually be

auto foo(ref T bar) {...}

but instead of giving an error when you pass it an rvalue, it would do the
equivalent of

auto temp = returnsRValue();
foo(temp);

so that foo would have an rvalue. You still wouldn't get any copying
happening, you'd only have to declare one function, and you wouldn't get a
combinatorial explosion of function declarations or template instantiations.
I believe that that is essentially what Andrei originally intended for auto
ref to be.

The problem is that we don't want to introduce yet another attribute to do
this. We could reuse auto ref for it, so you'd do

auto foo(auto ref T bar) {...}

but that either means that we redefine what auto ref does with templated
functions (which would be a problem, because it's actually useful there for
other purposes, because it's the closest thing that we have to perfect
forwarding at this point), or we make it so that auto ref does something
different with normal functions than it does with template functions, which
could be confusing, and you might actually like to be able to use the
non-templated auto ref solution with templated functions. It should be
possible _some_ of the time for the compiler to determine that it can optimize
the templated version into the non-templated one (i.e. when it can determine
that the forwarding capabilities of thet templated auto ref aren't used), but
it's not clear how well that will work, or whether it's an acceptable
solution.

Walter has suggested that we just redefine ref itself to do what I just
described rather than using auto ref or defining a new attribute. However,
both Andrei and I argued with him quite a bit over that, because that makes it
so that you can't tell whether a ref argument is intended to mutate what's
being passed in, or whether it's just an optimization (and you can't just use
const in all of the situations where you don't want the mutation, because D's
const is far more restrictive than C++'s const). Others agree with us, and
there are probably some that agree with Walter, but I don't 

Re: const ref parameters and r-value references

2014-05-04 Thread bearophile via Digitalmars-d-learn

Jonathan M Davis:

Andrei suggested auto ref to fix this problem, and Walter 
implemented it, but he misunderstood what Andrei had meant,


I missed this detail of the story :-)


Walter has suggested that we just redefine ref itself to do 
what I just
described rather than using auto ref or defining a new 
attribute. However,
both Andrei and I argued with him quite a bit over that, 
because that makes it
so that you can't tell whether a ref argument is intended to 
mutate what's

being passed in, or whether it's just an optimization


I think Ada was designed like that, and then have had to fix the 
language. So it's not a good idea.


Bye,
bearophile


Re: const ref parameters and r-value references

2014-05-04 Thread Mark Isaacson via Digitalmars-d-learn
Thanks for the insights! I suppose we'll get a chance to see 
where things stand at this year's dconf.


It's quite interesting that D's concept of r-values seems less 
developed than C++. Here's hoping that that only results in a 
better thought out solution.


Re: const ref parameters and r-value references

2014-05-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Sun, 04 May 2014 19:08:27 +
Mark Isaacson via Digitalmars-d-learn
digitalmars-d-learn@puremagic.com wrote:

 Thanks for the insights! I suppose we'll get a chance to see
 where things stand at this year's dconf.

 It's quite interesting that D's concept of r-values seems less
 developed than C++. Here's hoping that that only results in a
 better thought out solution.

Well, IIRC, rvalue-references are exactly what exactly what Andrei wants to
avoid due the large number of complications that the introduce to the
language. Ultimately, we want a solution in D that is simpler but still does
the job. We have simpler, but haven't quite sorted out the still does the
job part. I expect that we'll get there eventually, but we really should have
gotten there long before now and haven't.

- Jonathan M Davis


const ref parameters and r-value references

2014-05-02 Thread Mark Isaacson via Digitalmars-d-learn
I'm in the process of learning/practicing D and I noticed 
something that seems peculiar coming from a C++ background:


If I compile and run:

void fun(const ref int x) {
  //Stuff
}

unittest {
  fun(5); //Error! Does not compile
}

I get the specified error in my unit test. I understand that the 
cause is that I've attempted to bind ref to an r-value, what's 
curious is that in C++, the compiler realizes that this is a 
non-issue because of 'const' and just 'makes it work'. Is there a 
rationale behind why D does not do this? Is there a way to write 
'fun' such that it avoids copies but still pledges 
const-correctness while also allowing r-values to be passed in?


Thanks in advance!


Re: const ref parameters and r-value references

2014-05-02 Thread via Digitalmars-d-learn

On Friday, 2 May 2014 at 08:17:09 UTC, Mark Isaacson wrote:
I'm in the process of learning/practicing D and I noticed 
something that seems peculiar coming from a C++ background:


If I compile and run:

void fun(const ref int x) {
  //Stuff
}

unittest {
  fun(5); //Error! Does not compile
}

I get the specified error in my unit test. I understand that 
the cause is that I've attempted to bind ref to an r-value, 
what's curious is that in C++, the compiler realizes that this 
is a non-issue because of 'const' and just 'makes it work'. Is 
there a rationale behind why D does not do this? Is there a way 
to write 'fun' such that it avoids copies but still pledges 
const-correctness while also allowing r-values to be passed in?


There is `auto ref`, but it only works for templates and is 
somewhat different:


void fun()(auto ref const int x) {
// Stuff
}

unittest {
fun(5);// pass by value
int a = 5;
fun(a);// pass by ref
}

It generates two functions, with and without ref respectively.

Allowing rvalues to bind to ref (not only const) has been 
discussed on several occasions, but I don't remember the outcome. 
Here is one discussion:


http://forum.dlang.org/thread/ntsyfhesnywfxvzbe...@forum.dlang.org


Re: const ref parameters and r-value references

2014-05-02 Thread Mark Isaacson via Digitalmars-d-learn
Auto ref parameters seem to be just what I need. Thanks! I'd 
still be curious if anyone has additional information regarding 
the rationale at play (I'm spoiled, reading TDPL and having each 
decision explained in text).


Re: const ref parameters and r-value references

2014-05-02 Thread Meta via Digitalmars-d-learn

On Friday, 2 May 2014 at 21:29:51 UTC, Mark Isaacson wrote:
Auto ref parameters seem to be just what I need. Thanks! I'd 
still be curious if anyone has additional information regarding 
the rationale at play (I'm spoiled, reading TDPL and having 
each decision explained in text).


The C++ way was deemed not good enough, but nobody knows how to 
do it better.