View mode: basic / threaded / horizontal-split · Log in · Help
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Sat, Jan 5, 2013 at 3:05 AM, Andrei Alexandrescu <
SeeWebsiteForEmail@erdani.org> wrote:

>
> All - one more look please: http://dlang.org/dlangspec.**mobi<http://dlang.org/dlangspec.mobi>


Calibre does not open it here (Linux, KDE) not does it accept to convert
it.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
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 ;)
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Saturday, 5 January 2013 at 12:58:49 UTC, js.mdnq wrote:
> You are saying because "visually" foo(S(2)) leaves the "scope" 
> it is different than the others.


No, he is saying so because the LANGUAGE (and I don't mean the 
_compiler_) defines what "scope" means, and it also defines when 
anything enters/leaves some scope.

It also defines the lifetimes of variables, and for structs, 
that's bounded to their scope.


Your perception of what *COULD* have been an alternate definition 
(or implementation) has zero bearing on anything, because that's 
not what it means in D, period.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Friday, 4 January 2013 at 19:15:03 UTC, Ali Çehreli wrote:
> 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...

Why do you think there is no semantic difference?

> 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.

Even if one particular function makes some side effects and does 
not care by taking ref parameter that changes may be discarded, 
it is a source of bugs in general, when taking argument by ref 
means that passed object must be modified and changes need to be 
preserved.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
Al 05/01/13 10:10, En/na Philippe Sigaud ha escrit:
> 
>  Calibre does not open it here (Linux, KDE) not does it accept to convert it.
> 

No problem open the last http://dlang.org/dlangspec.mobi (built by andralex) with Calibre v0.8.38 (Linux 64-bit, Mate)

-- 
Jordi Sayol
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
Am 04.01.2013 20:35, schrieb deadalnix:
> On Friday, 4 January 2013 at 19:15:03 UTC, Ali Çehreli wrote:
>> > 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 is where things are subtle. Depending on the calling convention, the struct may be returned
> into a register. In such case it has no storage in memory.
> 

Although, nothing stops the compiler from initializing a struct in a register either. At least when
the constructor can be inlined.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Saturday, 5 January 2013 at 18:38:31 UTC, Mehrdad wrote:
> On Saturday, 5 January 2013 at 12:58:49 UTC, js.mdnq wrote:
>> You are saying because "visually" foo(S(2)) leaves the "scope" 
>> it is different than the others.
>
>
> No, he is saying so because the LANGUAGE (and I don't mean the 
> _compiler_) defines what "scope" means, and it also defines 
> when anything enters/leaves some scope.
>
> It also defines the lifetimes of variables, and for structs, 
> that's bounded to their scope.
>
>
> Your perception of what *COULD* have been an alternate 
> definition (or implementation) has zero bearing on anything, 
> because that's not what it means in D, period.


Oh please, 90% of the discussions on here are about what d is 
doing, should do, and will do, period!

The discussion came about because a change in the 
compiler/language and regardless of how you want to spin it, D's 
language specification is not set in stone and is not implemented 
perfectly in the compiler... and even if it were, it doesn't then 
mean that it does it the best way.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Sat, Jan 5, 2013 at 9:17 PM, Jordi Sayol <g.sayol@yahoo.es> wrote:

> Al 05/01/13 10:10, En/na Philippe Sigaud ha escrit:
> >
> >  Calibre does not open it here (Linux, KDE) not does it accept to
> convert it.
> >
>
> No problem open the last http://dlang.org/dlangspec.mobi (built by
> andralex) with Calibre v0.8.38 (Linux 64-bit, Mate)
>
>
Calibre 0.8.64 here. Still does not work.
(...)
I updated to 0.9.13 (latest version) and it works, yeah!

Andrei, would that be possible to give us access to the .css that gives the
mobi file its global appearance? I'd like D-related mobi/epub that I create
to have the same look-and-feel.
January 05, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Saturday, 5 January 2013 at 21:24:48 UTC, js.mdnq wrote:
>
> Oh please, 90% of the discussions on here are about what d is 
> doing, should do, and will do, period!
>
> The discussion came about because a change in the 
> compiler/language and regardless of how you want to spin it, 
> D's language specification is not set in stone and is not 
> implemented perfectly in the compiler... and even if it were, 
> it doesn't then mean that it does it the best way.

The root problem, which I mentioned in an earlier post in this 
thread (that unfortunately caused the diversion into patching up 
the .mobi file), is that D does not actually have a specification 
because the specification is not being properly managed. To me, 
this is a significant problem that needs to be taken on as soon 
as possible - we need a solid official specification that 
contains at least revision numbers for tracking purposes and 
linking to the compiler releases, among other obvious advantages.

What we have ATM is not being managed in a sane and efficient way 
and can never be pinned down. The specification is actually 
spread out between what is on this web site, partly hidden away 
in forum postings, and what is in the TDPL book (and I probably 
missed a location or two). I cannot think of a situation much 
worse than this, yet here we are. If we can survive with this, 
then imagine how much better we'll be with at least some thought 
put into consolidating the specification into a managed document.

Rather than arguing endlessly over something that has no answer, 
we instead need to get organized and pin down the specification 
into a well managed form. We can do this by doing exactly the 
same things that we're doing with implementing the development 
and release process, i.e., we need a process for managing the 
specification, and we need a document that can be managed in 
similar ways (although likely not identical) to how the software 
is now being manged.

I'm certain there are a few people reading this who know what I'm 
talking about, and who have much more experience in how to manage 
something like a specification. So if anyone wants to step up and 
lend a hand, now may be a good time. There's really no reason for 
delaying what needs to be done.

--rt
January 06, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
On Saturday, January 05, 2013 13:58:48 js.mdnq wrote:
> 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.

No offense. I'm afraid that you simply have no clue what you're talking about. 
Scope is defined by the language. And temporaries leave scope when the 
statement that they're in completes. And these examples in both D and C++ show 
that that's the case:

------------
import std.stdio;

struct S
{
   this(int i)
   {
       this.i = i;
       writeln("Constructed!");
   }

   ~this()
   {
       writeln("Destroyed!");
   }

   int i;
}

void foo(S s)
{
   writeln("foo!");
}

void main()
{
   writeln("before");
   foo(S(5));
   writeln("after");
}
------------

------------
#include <cstdio>
using namespace std;

struct S
{
   S(int i)
   {
       this->i = i;
       printf("Constructed!\n");
   }

   ~S()
   {
       printf("Destroyed!\n");
   }

   int i;
};

void foo(S s)
{
   printf("foo!\n");
}

int main()
{
   printf("before\n");
   foo(S(5));
   printf("after\n");

   return 0;
}
------------

They both print

before
Constructed!
foo!
Destroyed!
after

If the struct literal continued to exist after the call to foo, "Destroyed!" 
would have printed after "after," but it printed before "after" in both cases.

This is required by the language, and it's precisely why doing things like 
taking the address of a temporary are so incredibly foolish to do.

- Jonathan M Davis
1 2 3 4 5 6
Top | Discussion index | About this forum | D home