Jump to page: 1 2
Thread overview
Binding rvalues to const ref in D
Oct 19, 2016
Atila Neves
Oct 19, 2016
Chris Wright
Oct 19, 2016
Atila Neves
Oct 19, 2016
Chris Wright
[OT] Re: Binding rvalues to const ref in D
Oct 20, 2016
Nick Sabalausky
Oct 20, 2016
Nick Sabalausky
Oct 20, 2016
Nick Sabalausky
Oct 20, 2016
Ethan Watson
Oct 20, 2016
Manu
Oct 20, 2016
Ethan Watson
Oct 20, 2016
Manu
Oct 19, 2016
Johan Engelen
Oct 19, 2016
Guillaume Piolat
Oct 19, 2016
Ali Çehreli
Oct 20, 2016
Nick Sabalausky
Oct 20, 2016
Ali Çehreli
Oct 20, 2016
bitwise
October 19, 2016
New post since the the last one was already off-topic. Continued from:

http://forum.dlang.org/post/nu7mv8$mqu$1@digitalmars.com

I get the feeling that people are talking past each other. I'm going to give my view of the situation and everybody can correct me if I'm wrong / throw tomatoes at me.code

On the one hand some people want rvalues to bind to const ref. I can only assume that they want this because they want to pass rvalues to a function efficiently - i.e. put a pointer in a register. It might also be due to familiarity with C++ but I speculate. If indeed I'm right, then I wonder if it's by instinct or if it's been measured versus passing a struct by value. I just wrote this:

struct Vector { float x, y, z; }
float silly(Vector v) { return v.x * 5; }

float test() {
    Vector v;
    return silly(Vector(1, 2, 3)) * 7;
}

Yes, it's a stupid example. But ldc2 -O3 gives me this for `silly`:

movq   rax,xmm0
movd   xmm0,eax
mulss  xmm0,DWORD PTR [rip+0x0]
ret

It's a bit longer than if I passed in a float directly:

mulss  xmm0,DWORD PTR [rip+0x0]
ret

But... there's no copying or moving of the entire struct. C++ (also passing by value, I just hand-tranlated the code) is similar but for some reason was better at optimising:

mulss  xmm0,DWORD PTR [rip+0x0]
ret
nop

Again, no copying or moving. Which is what I expected. Granted, real-life code might be complicated enough to make matters a lot worse. I'm just wondering out loud how likely that is to happen and how big of an impact on total performance that'll have. My question is: do you _really_ need rvalues to bind to const ref for performance? If not, what _do_ you need it for? Is it an instinctive reaction against passing structs by value from C++98 days?

It's been mentioned that one might not get a say on how a function is declared if calling, say, C++ from D. That's a fair argument, and one I've not heard a solution for yet. Maybe allow rvalues to bind to const ref in `extern(C++)`? I don't know, I'm thinking out "loud".


On the other hand we have the "rvalues binding to const ref => rvalue references or other complicated mechanisms for figuring out whether or not the const ref is an rvalue". This seems to have not been explained correctly. I'm not blaming anyone, I just tried yesterday and failed as well.

The situation is this: if one wants move semantics, one must know when one can move. Because rvalues bind to const& in C++, you never know whether the const& is an lvalue or rvalue. The solution to this was rvalue references, which are refs that can _only_ bind to rvalues. That way you know that the origin was an rvalue an wahey, move semantics. They complicated the language significantly. Did you know there's more than one kind of rvalue in C++? Oh yes:

http://en.cppreference.com/w/cpp/language/value_category

Do we want that? I don't.

Summary:

* rvalues don't bind to const ref because if they did there'd be ambiguity, and to solving that problem would make the language more complicated.
* Knowing when passed-in parameters were actually rvalues turns out to be something compilers want to do because performance.
* It'd be nice if D could call C++ functions that take const& with rvalues

Tomato time?

Atila




October 19, 2016
On Wed, 19 Oct 2016 15:18:36 +0000, Atila Neves wrote:

> The situation is this: if one wants move semantics, one must know when one can move. Because rvalues bind to const& in C++, you never know whether the const& is an lvalue or rvalue.

To clarify:

You copy lvalues instead of moving them. You move rvalues instead of copying them. This has an impact when you assign or pass a ref struct variable to a non-ref variable.

As a practical matter, whenever I come up against a case where I need to pass something by reference but it's an rvalue, I assign a temporary variable (after scratching my head at an inscrutable message because, hey, everyone's using templates right now and the error message just tells me that I can't pass a DateTime to something expecting a ref T).

So it seems like the compiler could take care of this by only providing lvalue references but automatically creating those temporary variables for me. It's going to create an extra copy that might not be needed if there were a special rvalue reference type modifier, but why should I care? It's exactly as efficient as the code the compiler forces me to write.

This is what Ethan Watson has suggested, too.
October 19, 2016
On Wednesday, 19 October 2016 at 15:18:36 UTC, Atila Neves wrote:
>
> Yes, it's a stupid example. But ldc2 -O3 gives me this for `silly`:

Great example, thanks, please more of that :)
https://github.com/ldc-developers/ldc/issues/1842

cheers,
  Johan

October 19, 2016
On Wednesday, 19 October 2016 at 15:18:36 UTC, Atila Neves wrote:
> My question is: do you _really_ need rvalues to bind to const ref for performance? If not, what _do_ you need it for? Is it an instinctive reaction against passing structs by value from C++98 days?

imho it's the compiler job to pass by value or ref. For a function that is inlined it should be able to make its on choice.
October 19, 2016
On 10/19/2016 08:18 AM, Atila Neves wrote:

> Did you know there's more
> than one kind of rvalue in C++? Oh yes:
>
> http://en.cppreference.com/w/cpp/language/value_category
>
> Do we want that?

NO!

My off-topic contribution to this thread: I won't be surprised when C++ will eventually be classified as a case of mass hysteria.

Ali

October 19, 2016
On Wednesday, 19 October 2016 at 15:58:23 UTC, Chris Wright wrote:
> On Wed, 19 Oct 2016 15:18:36 +0000, Atila Neves wrote:
>
>> The situation is this: if one wants move semantics, one must know when one can move. Because rvalues bind to const& in C++, you never know whether the const& is an lvalue or rvalue.
>
> To clarify:
>
> You copy lvalues instead of moving them. You move rvalues instead of copying them. This has an impact when you assign or pass a ref struct variable to a non-ref variable.

Then there's this:

void foo(ref Foo); //doesn't copy lvalues
void foo(Foo);

What's a ref struct variable?

> As a practical matter, whenever I come up against a case where I need to pass something by reference but it's an rvalue, I assign a temporary variable (after scratching my head at an inscrutable message because, hey, everyone's using templates right now and the error message just tells me that I can't pass a DateTime to something expecting a ref T).

I'm assuming this happens because you don't control the signature of the function you're calling and it takes by ref?

> So it seems like the compiler could take care of this by only providing lvalue references but automatically creating those temporary variables for me. It's going to create an extra copy that might not be needed if there were a special rvalue reference type modifier, but why should I care? It's exactly as efficient as the code the compiler forces me to write.
>
> This is what Ethan Watson has suggested, too.

Interesting. Also, I must have missed that suggestion.


Atila

October 19, 2016
On Wed, 19 Oct 2016 21:19:03 +0000, Atila Neves wrote:

> On Wednesday, 19 October 2016 at 15:58:23 UTC, Chris Wright wrote:
>> On Wed, 19 Oct 2016 15:18:36 +0000, Atila Neves wrote:
>>
>>> The situation is this: if one wants move semantics, one must know when
>>> one can move. Because rvalues bind to const& in C++,
>>> you never know whether the const& is an lvalue or rvalue.
>>
>> To clarify:
>>
>> You copy lvalues instead of moving them. You move rvalues instead of copying them. This has an impact when you assign or pass a ref struct variable to a non-ref variable.
> 
> Then there's this:
> 
> void foo(ref Foo); //doesn't copy lvalues void foo(Foo);
> 
> What's a ref struct variable?

A variable whose type is a struct and which has the `ref` modifier.

>> As a practical matter, whenever I come up against a case where I need to pass something by reference but it's an rvalue, I assign a temporary variable (after scratching my head at an inscrutable message because, hey, everyone's using templates right now and the error message just tells me that I can't pass a DateTime to something expecting a ref T).
> 
> I'm assuming this happens because you don't control the signature of the function you're calling and it takes by ref?

Right. For instance, binding query parameters with mysql-native. The thing you're binding is passed by reference and I'm not sure why.
October 20, 2016
On 10/19/2016 04:50 PM, Ali Çehreli wrote:
>
> My off-topic contribution to this thread: I won't be surprised when C++
> will eventually be classified as a case of mass hysteria.
>

That'll happen at the same time modern web technology stacks are classified similarly.

Much as I'd love to see that day, I'm not holding my breath...

But seriously, every time I look at anything going on in C++ the last several years, it looks more and more like it just simply wants to *be* D, takes a couple drunken steps in that direction, and falls flat on its face.

October 19, 2016
On 10/19/2016 10:53 PM, Nick Sabalausky wrote:

> [C++] just simply wants to *be*
> D, takes a couple drunken steps in that direction, and falls flat on its
> face.

That's too funny! :D

Ali

October 20, 2016
On 10/19/2016 07:04 PM, Chris Wright wrote:
>
> Right. For instance, binding query parameters with mysql-native. The
> thing you're binding is passed by reference and I'm not sure why.
>

It's been like that since mysql-native's original release, by the original author, some years ago.

I suspect the idea was a rudimentary ORM-like approach: to have the prepared statement params semi-permanently tied to actual variables (ie, "bound" to them). Ie, so you could re-exectute the same prepared statement with different values just by changing the values and calling `execPrepared` again, without calling any of the bind functions again.

I'd have to check whether or not that usage pattern currently works though.

« First   ‹ Prev
1 2