Re: meaning of "auto ref const"?

2016-12-20 Thread Picaud Vincent via Digitalmars-d-learn

On Tuesday, 20 December 2016 at 20:08:32 UTC, Ali Çehreli wrote:


If the purpose is optimization, the good news are


Yes it is :)

* Classes are already reference types so there is no lvalue or 
rvalue reference distinction there


Ok, this one is quite intuitive.


import std.stdio;
...


Thank you for the illustrative example, I have reproduced it.


There is a surprising difference in D:

In D, non-constness of an object seems to be more important in 
overload resolution: Notice how mutable lvalue above is passed 
to by-copy instead of the potentially-more-optimal by-const-ref 
above. D realizes that a mutable object is for mutation and 
because by-const-ref cannot mutate it, D passes it to the 
by-copy function. (This may be seen as a bug by some.)


Thank you for pointing out this. I was not aware of that, and for 
sure this is not the C++  behavior.


Interestingly, enabling the by-mutable-ref overload above, now 
the mutable object goes to by-ref and there is no automatic 
copy:


Ok, that is "moral" and without surprise.


--- rvalue ---
constructor   1
foo(by-copy)  1
destructor for1

--- mutable lvalue ---
constructor   2
foo(by-ref)   2
destructor for2

--- const lvalue ---
constructor   3
foo(by-ref-const) 3
destructor for3

Ali

[1] I have an issue with "rvalue reference" as rvalue 
references can be references to lvalues as well. :p


Thank you for your time and these valuable explanations, I learnt 
a lot.

--Vincent


Re: meaning of "auto ref const"?

2016-12-20 Thread Picaud Vincent via Digitalmars-d-learn

On Tuesday, 20 December 2016 at 19:24:32 UTC, Ali Çehreli wrote:
As a general rule, 'auto ref' should probably be const. If the 
purpose of 'ref' is so that the argument would be mutated, then 
allowing a copy of an rvalue to this function could very well 
be a bug:


struct S {
int i;
}

void foo()(auto ref S s) {
s.i = 42;  // <-- Cannot be observed if the arg is rvalue
}

void main() {
foo(S(1));
}


Thank you Ali! This is effectively a trap I had not realized, you 
probably save me from some long debugging time.


Re: meaning of "auto ref const"?

2016-12-20 Thread Ali Çehreli via Digitalmars-d-learn

On 12/18/2016 05:14 AM, Picaud Vincent wrote:

> Another interrogation for me, who come from C++, is how to translate
> into D:
>
> template void foo(T&& t);

If it means "rvalue reference"[1], then there is no equivalent is D 
because D does not allow references to rvalues, even if const.


If the purpose is optimization, the good news are

* Classes are already reference types so there is no lvalue or rvalue 
reference distinction there


* rvalue structs are automatically moved to functions when passed by-copy

import std.stdio;

struct S {
double i;
ubyte[1000] buf;
this(int i) {
this.i = i;
writefln("constructor   %s", i);
}
this(this) {
writef(  "post-blit %s -> ", i);
this.i += 0.1;
this.buf = buf.dup;
writeln(i);
}
~this() {
writefln("destructor for%s", i);
}
}

void foo(S s) {
writefln("foo(by-copy)  %s", s.i);
}

void foo(ref const(S) s) {
writefln("foo(by-ref-const) %s", s.i);
}

// UNCOMMENT THIS TO BE SURPRISED:
// void foo(ref S s) {
// writefln("foo(by-ref)   %s", s.i);
// }

void main() {
{
writeln("\n--- rvalue ---");
foo(S(1));
}
{
writeln("\n--- mutable lvalue ---");
auto s = S(2);
foo(s);
}
{
writeln("\n--- const lvalue ---");
const s = S(3);
foo(s);
}
}

According to the output, there is no post-blit executed for the rvalue:

--- rvalue ---
constructor   1
foo(by-copy)  1
destructor for1

--- mutable lvalue ---
constructor   2
post-blit 2 -> 2.1
foo(by-copy)  2.1
destructor for2.1
destructor for2

--- const lvalue ---
constructor   3
foo(by-ref-const) 3
destructor for3

There is a surprising difference in D:

* First, in C++, you cannot have both the by-copy and by-ref-to-const 
overload of a function: It would be ambiguous for rvalues.


* You can have that in D, which brings the interesting difference:

In D, non-constness of an object seems to be more important in overload 
resolution: Notice how mutable lvalue above is passed to by-copy instead 
of the potentially-more-optimal by-const-ref above. D realizes that a 
mutable object is for mutation and because by-const-ref cannot mutate 
it, D passes it to the by-copy function. (This may be seen as a bug by 
some.)


Interestingly, enabling the by-mutable-ref overload above, now the 
mutable object goes to by-ref and there is no automatic copy:


--- rvalue ---
constructor   1
foo(by-copy)  1
destructor for1

--- mutable lvalue ---
constructor   2
foo(by-ref)   2
destructor for2

--- const lvalue ---
constructor   3
foo(by-ref-const) 3
destructor for3

Ali

[1] I have an issue with "rvalue reference" as rvalue references can be 
references to lvalues as well. :p




Re: meaning of "auto ref const"?

2016-12-20 Thread Ali Çehreli via Digitalmars-d-learn
As a general rule, 'auto ref' should probably be const. If the purpose 
of 'ref' is so that the argument would be mutated, then allowing a copy 
of an rvalue to this function could very well be a bug:


struct S {
int i;
}

void foo()(auto ref S s) {
s.i = 42;  // <-- Cannot be observed if the arg is rvalue
}

void main() {
foo(S(1));
}

To contradict myself (and I hate when I do that! :p), the function may 
be using the rvalue in a non-const context, which would make the 
mutation observable:


struct S {
int i;

void sayIt() {
import std.stdio;
writeln(i);
}
}

void foo()(auto ref S s) {
s.i = 42;
s.sayIt();// <-- Here
}

// ...

Another one through the return value (but this time it's a copy anyway, 
perhaps defeating the 'ref' purpose):


// ...

S foo()(auto ref S s) {
s.i = 42;
return s;
}

void main() {
foo(S(1)).sayIt();  // <-- Here
}

Ali



Re: meaning of "auto ref const"?

2016-12-18 Thread Picaud Vincent via Digitalmars-d-learn

On Sunday, 18 December 2016 at 14:32:08 UTC, kinke wrote:

TypeInfo_Struct apparently requires (or used to require) an 
`int opCmp(ref const T rhs)` overload, i.e., a version taking 
the rhs lvalue argument by reference (see 
https://dlang.org/spec/operatoroverloading.html#compare). Note 
that there are other overloads afterwards which take the rhs 
argument by value, thereby allowing rhs rvalues too.


Thank you for your complementary answer and explanation. All 
these look less strange to me now.


Re: meaning of "auto ref const"?

2016-12-18 Thread Picaud Vincent via Digitalmars-d-learn

On Sunday, 18 December 2016 at 14:25:04 UTC, Basile B. wrote:

...
As you can see, auto ref is more flexible with the parameter. 
This make sense for templated functions.


Thank you for your detailed answer, things are perfectly clear 
now. Also sorry for the doc linksI should have found it before 
asking my question.


Re: meaning of "auto ref const"?

2016-12-18 Thread kinke via Digitalmars-d-learn

On Sunday, 18 December 2016 at 13:14:08 UTC, Picaud Vincent wrote:

bool opEquals()(auto ref const BigInt y) const pure @nogc
{
   return sign == y.sign && y.data == data;
}

my problem is that I do not understand the role/meaning of 
"auto" in this context.


See https://dlang.org/spec/template.html#auto-ref-parameters. 
It's used to end up with an `opEquals(ref const BigInt y)` for 
lvalue args (passed by reference) and with an `opEquals(const 
BigInt y)` for rvalue args (passed by value => implicitly moved 
in D (as they are rvalues)).


Moreover in the opCmp code, "auto" is not present anymore, 
which is an extra source of confusions for me.


int opCmp(ref const BigInt y) pure nothrow @nogc const
{
   // Simply redirect to the "real" opCmp implementation.
   return this.opCmp!BigInt(y);
}


TypeInfo_Struct apparently requires (or used to require) an `int 
opCmp(ref const T rhs)` overload, i.e., a version taking the rhs 
lvalue argument by reference (see 
https://dlang.org/spec/operatoroverloading.html#compare). Note 
that there are other overloads afterwards which take the rhs 
argument by value, thereby allowing rhs rvalues too.


Re: meaning of "auto ref const"?

2016-12-18 Thread Basile B. via Digitalmars-d-learn

On Sunday, 18 December 2016 at 13:14:08 UTC, Picaud Vincent wrote:

Reading std/bigint.d code:

https://github.com/dlang/phobos/blob/00c1cc3b0d354363793c8b419ce84da722578138/std/bigint.d#L589

I have seen this:

bool opEquals()(auto ref const BigInt y) const pure @nogc
{
   return sign == y.sign && y.data == data;
}

my problem is that I do not understand the role/meaning of 
"auto" in this context.



With auto ref, the parameter can be either a LValue or a RValue.
When passing a struct as auto ref, it's taken as ref.
for example:

struct Foo{this(this){writeln("copy");}}
struct Bar{@disable this(this);}
void testAsRef(T)(ref T t){}
void testAsValue(T)(T t){}
void testRefOrValue(T)(auto ref T t){}

Foo foo;
Bar bar;

testAsRef(1); // error 1 is not ref
testAsRef(foo); // ok, not copied
testAsRef(bar); // ok, not copied

testAsValue(1); // ok
testAsValue(foo); // ok but copied
testAsValue(bar); // error, could only be copied but postblit is 
disabled


testRefOrValue(1); // ok, not taken as ref
testRefOrValue(foo); // ok, not copied
testRefOrValue(bar); // ok, taken as ref

As you can see, auto ref is more flexible with the parameter. 
This make sense for templated functions.


meaning of "auto ref const"?

2016-12-18 Thread Picaud Vincent via Digitalmars-d-learn

Reading std/bigint.d code:

https://github.com/dlang/phobos/blob/00c1cc3b0d354363793c8b419ce84da722578138/std/bigint.d#L589

I have seen this:

bool opEquals()(auto ref const BigInt y) const pure @nogc
{
   return sign == y.sign && y.data == data;
}

my problem is that I do not understand the role/meaning of "auto" 
in this context.


Moreover in the opCmp code, "auto" is not present anymore, which 
is an extra source of confusions for me.


int opCmp(ref const BigInt y) pure nothrow @nogc const
{
   // Simply redirect to the "real" opCmp implementation.
   return this.opCmp!BigInt(y);
}

What is the rational?

-

Another interrogation for me, who come from C++, is how to 
translate into D:


template void foo(T&& t);