View mode: basic / threaded / horizontal-split · Log in · Help
January 04, 2013
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
Re: WTF did happen with struct constructor and ref in 2.061 ?
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
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:
> > 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.
1 2 3 4 5 6
Top | Discussion index | About this forum | D home