January 04, 2013
On Friday, 4 January 2013 at 04:32:46 UTC, Andrei Alexandrescu wrote:
> This is a misunderstanding and I confess I'm mildly miffed by it. The e-book is generated from the online documentation. $0.99 is the smallest price Amazon would allow any self-publication to be on their site. Some people (negligible as a source of income, but not few; the book makes it at times on top 100 bestseller list in its category) do find value in having the content on their Kindle, and are willing to pay one dollar for it, so there is value in having it there. To construe that as an awkward attempt to make money is quite a bit of a stretch.
>
>
> Andrei

Sorry, I didn't want to offend and I honestly never thought anyone was making money from it, I just never understood why it was on Amazon yet not on this website, so thanks for taking the time to explain why the e-book is on Amazon, it makes perfect sense now.

Perhaps an explanation such as "For your convenience, an e-book is available at Amazon ..." next to the fixed link is a good solution to prevent any possible misunderstandings.

No matter, I really do not want to get into this level of detail as it's of very limited significance right now. All I was attempting to point out was the need to move on with formalizing a process for managing the specification, and you've clearly acknowledged the desire to do exactly that. Once we have a better process in place, many old recurring problems will automatically go away.

--rt
January 04, 2013
On 2013-01-04 00:57, deadalnix wrote:

> This has been discussed, but I'm pretty sure nothing was really
> conclusive (especially when I read about auto ref).
>
> And even if it was, how come that this isn't advertised with some big
> red sign ? If a person that read the newsgroup like me didn't see that
> coming, what about any regular D user ?

I had the same problem. Thank god I saw this thread.

-- 
/Jacob Carlborg
January 04, 2013
On 2013-01-04 05:32, Andrei Alexandrescu wrote:
> On 1/3/13 11:26 PM, Rob T wrote:
>> On Friday, 4 January 2013 at 00:59:01 UTC, Andrei Alexandrescu wrote:
>>> What's the link?
>>>
>>
>> The bad link is also here, including the Amazon link.
>> http://dlang.org/spec.html
>>
>> The problem link and the Amazon e-book issue has been mentioned multiple
>> times before and as recently as Nov last year.
>
> I don't understand what the "issue" is.

There's a link on the top of that page, "Mobi ebook", which links to this page

http://www.digitalmars.com/d/2.0/dlangspec.mobi

That page results in a 404 page.

-- 
/Jacob Carlborg
January 04, 2013
On Thursday, 3 January 2013 at 23:40:39 UTC, Jonathan M Davis wrote:
> On Friday, January 04, 2013 00:20:58 deadalnix wrote:
>> I find myself with massive breakage in my codebase. I have a lot
>> of code doing stuff like foo(Bar(args)) where foo expect a ref
>> parameter. This used to work just fine, but now it do not.
>> 
>> This seems to me particularly dubious as the compiler introduce a
>> temporary to call the constructor on. Bar(args) HAVE an address.
>> 
>> Looking at the change log, I can't find anything relevant to the
>> subject. What the fuck did happen and why ?
>
> http://d.puremagic.com/issues/show_bug.cgi?id=9069
>
> It makes _no_ sense for struct literals to be treated as lvalues. They're
> temporaries, not variables. This has been discussed a number of times before
> and was finally fixed with 2.061. Previously, you got nonsensical behavior like
>
> struct S
> {
>  int i;
> }
>
> S foo(ref S s)
> {
>  return s;
> }
>
> S bar(int i)
> {
>  return S(i);
> }
>
> void main()
> {
>  S s = S(2);
>  foo(s); //compiles as it should
>  foo(S(5)); //compiles when it shouldn't
>  foo(bar(5)); //fails to compile as it should
> }
>
> There should be no difference between a struct literal and a struct returned by
> value from a function. Code which depended on struct literals being lvalues was
> depending on buggy behavior.
>
> - Jonathan M Davis


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));

It is known as substitution theory and the second simply has an implicit step(which also makes it easier to program as it reduces an extra line).

But if the 2nd case is invalid then so is the first. i.e., What ever example you show as "buggy" using a "struct literal" I should be able to do the same without using one. (that is, assuming the compiler itself is not buggy in some other way)


January 04, 2013
On Friday, 4 January 2013 at 12:12:53 UTC, js.mdnq wrote:
>
> There is no semantic difference between
>
> S s = S(2); foo(s)
>
> and
>
> foo(S(2));
>

In the first case dtor (if any) is called at the end of the scope, in the second after expression being evaluated. It also may influence optimization.

Consider this:

import std.stdio;

struct S { ~this() { writeln("dtor"); } }

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

void foo(S s)
{
	writeln("non-ref");
}

void one()
{
	S s;
	foo(s);
	writeln("end");
}

void two()
{
	foo(S());
	writeln("end");
}

void main()
{
	one();
	two();
}

Output is:

ref
end
dtor
ref
dtor
end

If dmd supports struct lvalues by creating a temporary, then this temporary would be passed by reference, be modified and immidiately thrown away (although it depends on what dmd actually did - I have the latest version now and cannot check old behavior). This can lead to bugs caused by changing structs and not saving their state.
January 04, 2013
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. Where there's no real difference is

foo(S(2));
foo(funcThatReturnsS());

and yet previously, if foo accepted its argument by ref, the first compiled and the second didn't. In both cases, you're dealing with a temporary. They shouldn't be treated any differently from one another, and as both are temporaries, both should be treated as rvalues.

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.

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), and anyone who wants that is going to want it for foo(funcThatReturnsS()) just as much as they want it for foo(S(2)), making it so that ref doesn't solve their problem anyway (not to mention, in both of those cases, the ref is completely unnecessary, because if the function doesn't use ref, a move should be done rather than a copy, meaning that having foo(S(2)) work where foo accepts by ref doesn't save you from any copies anyway).

The fact that struct literals have been treated as lvalues is just plain buggy. 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.

- Jonathan M Davis
January 04, 2013
On 1/4/13 6:11 AM, Jacob Carlborg wrote:
> On 2013-01-04 05:32, Andrei Alexandrescu wrote:
>> On 1/3/13 11:26 PM, Rob T wrote:
>>> On Friday, 4 January 2013 at 00:59:01 UTC, Andrei Alexandrescu wrote:
>>>> What's the link?
>>>>
>>>
>>> The bad link is also here, including the Amazon link.
>>> http://dlang.org/spec.html
>>>
>>> The problem link and the Amazon e-book issue has been mentioned multiple
>>> times before and as recently as Nov last year.
>>
>> I don't understand what the "issue" is.
>
> There's a link on the top of that page, "Mobi ebook", which links to
> this page
>
> http://www.digitalmars.com/d/2.0/dlangspec.mobi
>
> That page results in a 404 page.

Got it, thanks. Will fwd to Walter.

Andrei

January 04, 2013
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.
> Where there's no real difference is
>
> foo(S(2));
> foo(funcThatReturnsS());
>

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

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

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 ? Now it is like saying this is incorrect, here is the correct way. Ha, BTW, the correct way isn't implemented yet so we did break your code in unfixable way.

> 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),
> and anyone who wants that is going to want it for foo(funcThatReturnsS()) just
> as much as they want it for foo(S(2)), making it so that ref doesn't solve
> their problem anyway (not to mention, in both of those cases, the ref is
> completely unnecessary, because if the function doesn't use ref, a move should
> be done rather than a copy, meaning that having foo(S(2)) work where foo
> accepts by ref doesn't save you from any copies anyway).
>
> The fact that struct literals have been treated as lvalues is just plain
> buggy.

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.
> - Jonathan M Davis

January 04, 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

January 04, 2013
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.

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

In fact, this is even worse, french grammar specify that this should be a non-breaking space :D

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

You have to understand that Bar(1) within funcThatReturnsBar have a storage, but it is then moved when returned. It can be moved to a register for instance, so I can't take a reference.

In the example terms, 7FFFF1076298 is the location on stack of Bar(1). But this location don't exist anymore when you return. On x86, The value will be in EAX in this particular example, so it effectively cannot be referenced.