WTF did happen with struct constructor and ref in 2.061 ?

Ali Çehreli acehreli at yahoo.com
Fri Jan 4 11:15:02 PST 2013


On 01/04/2013 10:48 AM, deadalnix wrote:
 > On Friday, 4 January 2013 at 16:47:38 UTC, Jonathan M Davis wrote:

 >>> There is no semantic difference between
 >>>
 >>> S s = S(2); foo(s)
 >>>
 >>> and
 >>>
 >>> foo(S(2));
 >>
 >> There's a _huge_ difference between those two. In the first case, you
 >> have a
 >> variable which exists beyond the end of the function call. In the
 >> second, you
 >> have temporary which is destroyed as soon as the statement has 
completed.

Still, there is no semantic difference. I know this issue from C++. At 
first I had embraced it but I am not so sure anymore. The language is 
getting out of its way to protect the programmer. A language like C++ 
that gives so much freedom to do many other unsafe things...

Constructors and functions do not affect objects alone. However frowned 
upon, a function that is called on an S may have side-effects that are 
beyond the object itself. If foo() does s.bar() and S.bar has a 
side-effect, I wouldn't care about the changes on the rvalue object itself.

So, I think C++ could have allowed binding rvalues to references to 
non-const. I don't think I would be bothered with that. If I had fooled 
myself occasionally, so be it.

 >> Where there's no real difference is
 >>
 >> foo(S(2));
 >> foo(funcThatReturnsS());

Agreed.

 >>
 >
 > This may not have a storage :
 > foo(funcThatReturnsS());

I don't see that. funcThatReturnsS returns an S, which must have a 
storage as well.

 > This MUST have a storage (as this storage is passed to the ctor) :
 > foo(S(2));
 >
 > So it is in fact different.
 >
 >> Also, it's completely nonsensical for a function which is supposed to be
 >> taking its argument by ref to take temporaries. A function takes its
 >> argument
 >> by ref so that it can mutate it, and if it accepts rvalues, then you
 >> lose the
 >> changes, because you're not dealing with a variable that lasts 
beyond the
 >> statement that the function call is in.

Getting back to this issue: So what? I have one more bug in my code.

 > A function can take ref argument for performance reasons. A function
 > caller may not care about reading the changes.
 >
 > Yes, if it for performance, auto ref should be used, but why in the
 > first place a breaking change have been made BEFORE auto ref is sorted
 > out ?

I agree with all of that. (Although, the French grammar rule of that 
space before the question mark is hurting my eyes! :p)

 >> If the issue is that someone wants the function to avoid making copies
 >> of the
 >> argument if it's not necessary, then that's what auto ref is for (and
 >> why the
 >> discussion how to implement that for non-templated functions is so
 >> important),

I hope D's 'auto ref' solution solves this issue once and for all. :)

 > struct Bar {
 > uint i;
 >
 > this(uint foo) {
 > import std.stdio;
 > writeln(&this);
 > }
 > }
 >
 > void main() {
 > Bar(0);
 > }
 >
 >> There should be _zero_ difference between how a struct literal is
 >> treated and how the return value of a function is treated. Both are
 >> temporaries and should be treated as such.
 >>
 >
 > Code above show there is.

I don't see that. There is storage for the rvalue returned from 
funcThatReturnsBar() as well, no?

struct Bar {
     uint i;

     this(uint foo) {
         import std.stdio;
         writeln(&this);
     }
}

void foo(Bar bar)
{}

Bar funcThatReturnsBar()
{
     return Bar(1);
}

void main() {
     foo(Bar(0));
     foo(funcThatReturnsBar());
}

That program prints two addresses for me:

7FFFF1076290
7FFFF1076298

Ali



More information about the Digitalmars-d mailing list