www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - temporary objects are not allowed to be pass by ref anymore

reply "Denis Koroskin" <2korden gmail.com> writes:
What's a rationale behind an issue described bug 2621?
http://d.puremagic.com/issues/show_bug.cgi?id=2621

Why isn't it allowed anymore?

It broke quite a lot of my code. And while it is fixable by doing

auto tmp = someFunctionThatRetunsStruct();
someMethodThatAcceptsStructByReference(tmp);

it looks ugly and unnecessary.
Apr 19 2009
next sibling parent Mike Parker <aldacron gmail.com> writes:
Denis Koroskin wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621
 
 Why isn't it allowed anymore?
 
 It broke quite a lot of my code. And while it is fixable by doing
 
 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);
 
 it looks ugly and unnecessary.

Yeah, I was recently caught by this when moving some code over to D2, thinking I'd take advantage of some const refs. I was quite surprised when my code wouldn't compile. Consider: struct Foo { int x; Foo opAdd(const ref Foo lhs) { Foo f = {x + lhs.x}; return f; } ref Foo opAddAssign(const ref Foo lhs) { x += lhs.x; return f; } } Given Foo a, b and c, the following fails to compile: c += a + b; The work around is to add an overridden opAddAssign that takes a non-ref foo. Not pretty, especially when dealing with numerous methods. Rather defeats the purpose of const ref parameters, does it not? And it's far from intuitive, particularly when coming from C++.
Apr 19 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com> wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

Wow, that's pretty dumb. I use that a lot too.
Apr 19 2009
prev sibling next sibling parent downs <default_357-line yahoo.de> writes:
Denis Koroskin wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621
 
 Why isn't it allowed anymore?
 
 It broke quite a lot of my code. And while it is fixable by doing
 
 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);
 
 it looks ugly and unnecessary.

To resolve this, let's consider two suspicions I have: 1) People use 'ref' for speed. Fairly obvious. I do it too. :) 2) People don't use 'out' for speed. This seems obvious, since 'out' does _more_ work than 'ref'. 2a) 'out' has stronger semantic meaning than 'ref'. Because of this, I recommend allowing temporaries to be passed to 'ref' parameters, but not 'out' parameters. That way, you can still use 'out' to implement extraneous return values.
Apr 19 2009
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com> wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

I just thought of something. Why the hell should we keep C++'s "const ref" anyway? When you use "const ref" it means you want it to be read-only and fast to pass large structures. But why should the onus of passing value types byref be on the programmer? Why not make it so "const valuetype" will pass byval for smaller values and byref for larger, completely freeing the programmer from this tedious crap? It's not something that I care about, and the threshold of byval vs. byref differs from platform to platform. Let's nip this in the bud right now. A const value type parameter should automatically decide whether to pass by reference or not.
Apr 19 2009
next sibling parent Rainer Deyke <rainerd eldwood.com> writes:
Jarrett Billingsley wrote:
 Let's nip this in the bud right now.  A const value type parameter
 should automatically decide whether to pass by reference or not.

Suggested change: an 'in' parameter should be either by-value or by-reference at the compiler's discretion. There needs to be a way to explicitly specify pass-by-value for those few cases where there is a semantic difference between by-value and by-reference. -- Rainer Deyke - rainerd eldwood.com
Apr 19 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com> wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

I just thought of something. Why the hell should we keep C++'s "const ref" anyway? When you use "const ref" it means you want it to be read-only and fast to pass large structures. But why should the onus of passing value types byref be on the programmer? Why not make it so "const valuetype" will pass byval for smaller values and byref for larger, completely freeing the programmer from this tedious crap? It's not something that I care about, and the threshold of byval vs. byref differs from platform to platform. Let's nip this in the bud right now. A const value type parameter should automatically decide whether to pass by reference or not.

I suggested that change. First let me clarify that the suggestion above cannot work. Due to aliasing, leaving it to the compiler to choose between by-value and by-reference leads to functions breaking when the size of the object changes, which is unacceptable. struct S { int x; ... } void foo(const S s1, ref S s2) { s1.x = 5; s2.x = 6; } S s; foo(s, s); // messed up Now onto why ref was disallowed to bind to an rvalue. This is because some functions take things by ref intending to change them. Passing an rvalue is in such cases a bug. I agree there are functions that only want to use ref for speed purposes. I suggested Walter to use ref? for those. ref? means it could be an rvalue or an lvalue. Andrei
Apr 19 2009
next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
On 19/04/2009 22:52, Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com>
 wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

I just thought of something. Why the hell should we keep C++'s "const ref" anyway? When you use "const ref" it means you want it to be read-only and fast to pass large structures. But why should the onus of passing value types byref be on the programmer? Why not make it so "const valuetype" will pass byval for smaller values and byref for larger, completely freeing the programmer from this tedious crap? It's not something that I care about, and the threshold of byval vs. byref differs from platform to platform. Let's nip this in the bud right now. A const value type parameter should automatically decide whether to pass by reference or not.

I suggested that change. First let me clarify that the suggestion above cannot work. Due to aliasing, leaving it to the compiler to choose between by-value and by-reference leads to functions breaking when the size of the object changes, which is unacceptable. struct S { int x; ... } void foo(const S s1, ref S s2) { s1.x = 5; s2.x = 6; } S s; foo(s, s); // messed up Now onto why ref was disallowed to bind to an rvalue. This is because some functions take things by ref intending to change them. Passing an rvalue is in such cases a bug. I agree there are functions that only want to use ref for speed purposes. I suggested Walter to use ref? for those. ref? means it could be an rvalue or an lvalue. Andrei

that does not compile. you tried to change a *const* struct...
Apr 19 2009
parent =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Yigal Chripun wrote:
 On 19/04/2009 22:52, Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com>
 wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

I just thought of something. Why the hell should we keep C++'s "const ref" anyway? When you use "const ref" it means you want it to be read-only and fast to pass large structures. But why should the onus of passing value types byref be on the programmer? Why not make it so "const valuetype" will pass byval for smaller values and byref for larger, completely freeing the programmer from this tedious crap? It's not something that I care about, and the threshold of byval vs. byref differs from platform to platform. Let's nip this in the bud right now. A const value type parameter should automatically decide whether to pass by reference or not.

I suggested that change. First let me clarify that the suggestion above cannot work. Due to aliasing, leaving it to the compiler to choose between by-value and by-reference leads to functions breaking when the size of the object changes, which is unacceptable. struct S { int x; ... } void foo(const S s1, ref S s2) { s1.x = 5; s2.x = 6; } S s; foo(s, s); // messed up Now onto why ref was disallowed to bind to an rvalue. This is because some functions take things by ref intending to change them. Passing an rvalue is in such cases a bug. I agree there are functions that only want to use ref for speed purposes. I suggested Walter to use ref? for those. ref? means it could be an rvalue or an lvalue. Andrei

that does not compile. you tried to change a *const* struct...

int foo (const S s1, ref S s2) { s2.x = 6; return s1.x; } S s; s.x = 3; x = foo (s, s); // messed up Jerome - -- mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.fr -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAknst54ACgkQd0kWM4JG3k+8QwCeP7ndr2Byqx4JtV+MgGhpwZrR R0IAniskBcRZHr88+KH3ZPvx14jgen6z =Op0n -----END PGP SIGNATURE-----
Apr 20 2009
prev sibling next sibling parent Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Sun, Apr 19, 2009 at 8:41 AM, Denis Koroskin <2korden gmail.com> 
 wrote:
 What's a rationale behind an issue described bug 2621?
 http://d.puremagic.com/issues/show_bug.cgi?id=2621

 Why isn't it allowed anymore?

 It broke quite a lot of my code. And while it is fixable by doing

 auto tmp = someFunctionThatRetunsStruct();
 someMethodThatAcceptsStructByReference(tmp);

 it looks ugly and unnecessary.

I just thought of something. Why the hell should we keep C++'s "const ref" anyway? When you use "const ref" it means you want it to be read-only and fast to pass large structures. But why should the onus of passing value types byref be on the programmer? Why not make it so "const valuetype" will pass byval for smaller values and byref for larger, completely freeing the programmer from this tedious crap? It's not something that I care about, and the threshold of byval vs. byref differs from platform to platform. Let's nip this in the bud right now. A const value type parameter should automatically decide whether to pass by reference or not.

I suggested that change. First let me clarify that the suggestion above cannot work. Due to aliasing, leaving it to the compiler to choose between by-value and by-reference leads to functions breaking when the size of the object changes, which is unacceptable. struct S { int x; ... } void foo(const S s1, ref S s2) { s1.x = 5; s2.x = 6; } S s; foo(s, s); // messed up Now onto why ref was disallowed to bind to an rvalue. This is because some functions take things by ref intending to change them. Passing an rvalue is in such cases a bug. I agree there are functions that only want to use ref for speed purposes. I suggested Walter to use ref? for those. ref? means it could be an rvalue or an lvalue.

Aside from the real issue at hand, ref? nees some other notation. Using a question mark here makes it look appalling, and kludgy. One also feels it's an interrogative of some kind.
Apr 19 2009
prev sibling next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Andrei Alexandrescu wrote:
...
 Now onto why ref was disallowed to bind to an rvalue. This is because 
 some functions take things by ref intending to change them. Passing an 
 rvalue is in such cases a bug.
 
 I agree there are functions that only want to use ref for speed 
 purposes. I suggested Walter to use ref? for those. ref? means it could 
 be an rvalue or an lvalue.
 
 
 Andrei

Since passing by const ref cannot change the parameter, is it possible to allow that for rvalues?
Apr 19 2009
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-04-19 15:52:02 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Now onto why ref was disallowed to bind to an rvalue. This is because 
 some functions take things by ref intending to change them.

True.
 Passing an rvalue is in such cases a bug.

I disagree. Function modify the temporary value, then the value is forgotten. It's just like calling a function and ignoring the returned value. It could be a bug, but it may not. For instance, a function may just be performing some destructive operation on the argument, in which case a temporary rvalue may very-well be appropriate since you are unlikely to need the result afterwards. Even C++0x saw the need and added rvalue non-const reference. <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html> -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 25 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 19 Apr 2009 23:52:02 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Now onto why ref was disallowed to bind to an rvalue. This is because  
 some functions take things by ref intending to change them. Passing an  
 rvalue is in such cases a bug.

 I agree there are functions that only want to use ref for speed  
 purposes. I suggested Walter to use ref? for those. ref? means it could  
 be an rvalue or an lvalue.


 Andrei

I don't understand why it is a bug, could you please elaborate on it? But anyway, why disallow pass-by-const-ref? It won't be modified anyway! struct Rect { int x, y, w, h; } Rect get() { Rect r; return r; } void pass(ref const(Rect) rect) { } void main() { pass(get()); } Error: function test.pass (ref const(Rect) rect) does not match parameter types (Rect) Error: get() is not an lvalue Also note that if you are right, and modifying a temporary is a bug, then C++ is in a winning position here, because its const system is tail-const, and that's exactly what is required here - you can't modify a variable, but you can mofify whatever it points to. We could have this behavior, too, by passing final-ref, not const-ref. Final qualifier means that an object it is applied to won't be modified, but it makes no statements about transitivity. Essentially, that's what C++ const does. Here is an example: struct RefCounted(T) { T* obj; // includes "int numReferences;" intrusively. } void passObject(ref final(RefCounted!(Foo)) foo) { auto copy = foo; // increments reference counter. Note that this don't modify the foo itself, only object which is available through it. } // passObject(new Foo()); // doesn't work, can we do anything with it? I'd like to hear your ideas. passObject(RefCounted!(new Foo())); // allowed!
Apr 29 2009