January 05, 2013
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
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
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
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
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
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
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
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
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
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