WTF did happen with struct constructor and ref in 2.061 ?

js.mdnq js_adddot+mdng at gmail.com
Sat Jan 5 04:58:48 PST 2013


On Friday, 4 January 2013 at 20:59:44 UTC, Jonathan M Davis wrote:
> On Friday, January 04, 2013 21:47:42 js.mdnq wrote:
>> On Friday, 4 January 2013 at 16:47:38 UTC, Jonathan M Davis 
>> wrote:
>> > On Friday, January 04, 2013 13:12:52 js.mdnq wrote:
>> >> can you show an example of such a bug? I assume you mean 
>> >> that a
>> >> "struct literal" ends up being a local object and a ref to 
>> >> it
>> >> can
>> >> easily become invalid?(in your example this is not possible
>> >> inside main). But your example basically contradicts what 
>> >> you
>> >> say.
>> >> 
>> >> 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.
>> 
>> Nope, sorry, it's not. That is only a compiler optimization. 
>> Just
>> because the compiler decides to do something to make them
>> different does not mean they are. The compiler could easily 
>> just
>> make S(2) null for no obvious reason because it wants to.
>> 
>> But if the compiler decides to make a different because of some
>> reason(such as optimization then it also can decide to not do 
>> so.
>> 
>> For example, tell me why the compiler can't just expand
>> 
>> foo(S(2));
>> 
>> to
>> 
>> S ___s = S(2);
>> foo(___s)
>> 
>> where ___s is hidden?
>
> S(2) _must_ leave scope after the statement foo(S(2)) 
> completes, whereas with
>
> S s = S(2);
> foo(s);
>
> the variable must continue to exist after foo(s) completes. 
> That's
> fundamentally different. We're _not_ talking about compiler 
> optimizations here.
> We're talking about the semantics of how the code works. And 
> creating a
> variable on the stack would change the code's semantics, 
> especially because
> foo(S(2)) should involve a move operation, whereas creating a 
> variable on the
> stack would require that the object be destroyed after the call 
> to foo. But
> even if declaring a hidden variable didn't change the 
> semantics, __s must be
> destroyed once the statement with foo has completed, so it 
> won't exist beyond
> the call to foo (it can't or it would alter the semantics of 
> the code), so
> it's still fundamentally different from declaring a variable 
> and passing it to
> foo, since the variable must continue to exist afterwards 
> whereas the
> temporary must be gone.
>
> - Jonathan M Davis


Nope, technically the "struct literal" does not go out of scope 
because it exists on the stack till the end of the outer scope... 
just as the local variable does. As I said, it is equivalent, due 
to the substitution principle to the hidden variable:

S s = S(2); foo(s) <==> foo(S(2))

because

foo(S(2)) can be shorthand for "hidden S __s = S(2); foo(s);"

(so, computationally these would all(or should) produce identical 
results).

You are saying because "visually" foo(S(2)) leaves the "scope" it 
is different than the others. This is true, but only visually(or 
syntactically). But the compiler could give you access to the 
hidden variable and then you would be wrong(it would not go out 
of scope).

Scope is not a physical but logical syntactical construct imposed 
by the compiler to help the user break a complex structure into 
nested units.

an only possibility would be something like:

e.g., we could have (pseudo)

   S s = S(2);
   foo(s);
   clear(s);

identical to

   hidden S __s = S(2); // hidden
   foo(__s);  // but seen has foo(S(2)) by user
   clear(__s); // hidden


and so both cases, as the original are the same.

The only way you would be right is if we had:


   hidden S __s = S(2); // hidden
   foowrap(__s);  // but seen has foo(S(2)) by user

   foowrap(ref S s) if (s is hidden) { foo(s); clear(s); } else { 
foo(s); }

BUT then we could still have

   S s = S(2);
   foowrap(s);


The proof is in the pudding:

The statement:

foo(S(2));

causes the compiler to "create" the struct S(2) on the stack at 
some location or puts the value into registers(these methods are 
essentially identical, at the very least for our purpose, one 
being faster and having some limitations). We'll assume S(2) 
exists on the stack as an identical* argument can be made for the 
registers

foo is passed a ptr to a memory location on the stack. foo does 
what it does and returns. S(2) still exists at the same memory 
location on the stack after the return call(possibly modified).

Now, take the statement:

S s = S(2);
foo(s);

The exact same argument is used except we would replace S(2) with 
s so to speak. The compiler "creates" s on the stack, passes it 
to foo, and returns.

Both cases the stack is "cleaned" up at the end of the scope. So, 
the difference you are talking about is only due to the compiler 
hiding the variable. To show that it is not we could have a 
compiler construct:

foo(S(2));
foo!LastArgument; // (the hidden variable used by the compiler)

in which case, using the notation I've used before,

foo!LastArgument == __s;

Hence, such a **compiler** construct rectifies the issue you are 
talking about which proves that with foo(S(2)), S(2) only goes 
out of scope logically due to the compiler not providing such a 
construct but what I have talked about with the stack/registers 
shows that they do not go out of scope physically(so to speak).

I mean, I agree with you, except the part about "fundamental", in 
the statement you have said, but it is a different argument as it 
is all about how the compiler deals with it, which is what I said 
initially that it is part of the compiler but there is no 
semantic difference.

Obviously there is a symbolic difference, there is a difference 
in syntax, but those differences are for wusses. Real men see 
things abstractly and realize that function is more important 
than form! (well, unless we are talking about women then it 
becomes much more difficult ;)













More information about the Digitalmars-d mailing list