Re: Passing Appender by value

2013-06-22 Thread Andrej Mitrovic
On 6/22/13, Andrej Mitrovic andrej.mitrov...@gmail.com wrote:
 I just learned today that passing Appender by value does not have the
 semantics I thought it would:

 -
 import std.array;
 import std.stdio;

 void call(Appender!(int[]) buffer)
 {
 buffer.put(1);
 }

 void main()
 {
 Appender!(int[]) buffer;
 writeln(buffer.data);  // writes [], it's empty
 }
 -

WRONG example, there's a missing call there, I meant:

-
import std.array;
import std.stdio;

void call(Appender!(int[]) buffer)
{
buffer.put(1);
}

void main()
{
Appender!(int[]) buffer;
call(buffer);
writeln(buffer.data);  // writes [], it's empty
}
-


Re: Passing Appender by value

2013-06-22 Thread Andrej Mitrovic
On 6/22/13, Andrej Mitrovic andrej.mitrov...@gmail.com wrote:
 Appender!(int[]) buffer;
 call(buffer);
 writeln(buffer.data);  // writes [], it's empty

Apparently it's the same thing as the old AA problem. Essentially the
buffer would have to be initialized first by appending:

-
import std.array;
import std.stdio;

void call(Appender!(int[]) buffer)
{
buffer.put(1);
}

void main()
{
Appender!(int[]) buffer;
call(buffer);
assert(buffer.data.empty);  // passes

call(buffer);
assert(buffer.data.empty);  // still passes

buffer.put(2);
call(buffer);
assert(buffer.data == [2, 1]);  // now it finally went through
}
-

It has something to do with null-initialization. I remember the
discussion about this problem with hashes, I just can't remember if
there was a bug report about it to link to.


Re: Passing Appender by value

2013-06-22 Thread Diggory

On Saturday, 22 June 2013 at 13:48:53 UTC, Andrej Mitrovic wrote:

On 6/22/13, Andrej Mitrovic andrej.mitrov...@gmail.com wrote:

Appender!(int[]) buffer;
call(buffer);
writeln(buffer.data);  // writes [], it's empty


Apparently it's the same thing as the old AA problem. 
Essentially the

buffer would have to be initialized first by appending:

-
import std.array;
import std.stdio;

void call(Appender!(int[]) buffer)
{
buffer.put(1);
}

void main()
{
Appender!(int[]) buffer;
call(buffer);
assert(buffer.data.empty);  // passes

call(buffer);
assert(buffer.data.empty);  // still passes

buffer.put(2);
call(buffer);
assert(buffer.data == [2, 1]);  // now it finally went 
through

}
-

It has something to do with null-initialization. I remember the
discussion about this problem with hashes, I just can't 
remember if

there was a bug report about it to link to.


The problem occurs whenever the internal array is resized because 
what actually happens is that a new array is allocated and the 
contents copied over - the original Appender still references the 
original array (or in this case null). The last example only 
works because when you call put(2) it actually allocates an 
array large enough to hold at least another item as well.


As usual it can be solved by introducing an extra layer of 
indirection, either by passing by ref or by making Appender store 
a pointer to a range.


Re: Passing Appender by value

2013-06-22 Thread monarch_dodra

On Saturday, 22 June 2013 at 14:19:45 UTC, Diggory wrote:
The problem occurs whenever the internal array is resized 
because what actually happens is that a new array is allocated 
and the contents copied over - the original Appender still 
references the original array (or in this case null). The last 
example only works because when you call put(2) it actually 
allocates an array large enough to hold at least another item 
as well.


As usual it can be solved by introducing an extra layer of 
indirection, either by passing by ref or by making Appender 
store a pointer to a range.


No, it's not that bad, because the extra layer of indirection 
is already there. The problem is that said layer isn't actually 
initialized yet...


Re: Passing Appender by value

2013-06-22 Thread monarch_dodra

On Saturday, 22 June 2013 at 13:48:53 UTC, Andrej Mitrovic wrote:

On 6/22/13, Andrej Mitrovic andrej.mitrov...@gmail.com wrote:

Appender!(int[]) buffer;
call(buffer);
writeln(buffer.data);  // writes [], it's empty


Apparently it's the same thing as the old AA problem. 
Essentially the

buffer would have to be initialized first by appending:


Yeah... same old, same old.

I think you can work around the problem using appender:
auto buffer = appender!(int[])();

This is off memory, so not 100% guaranteed, but I remember this 
worked for me last time *I* ran into this problem.


Indeed, this is a recurring problem in D with non-initialized 
reference types, AA's, Appender, Containers...


The fact there is no standardized way to make a call for run-time 
intialization with no arguments doesn't help either. I had made a 
request for having an explicit runtime constructor that takes no 
arguments:

http://forum.dlang.org/thread/bvuquzwfykiytdwsq...@forum.dlang.org
Didn't really get anywhere though...

In any case, I think this is a ***HUGE*** problem for D (my N°1 
problem anyways). static opCall() kind of helps, but it's not 
quite a constructor...


I think we're kind of doomed to keep this issue around 
unresolved, biting users in the ass *everyday*, for still quite 
some time :(


Re: Passing Appender by value

2013-06-22 Thread Andrej Mitrovic
On 6/22/13, monarch_dodra monarchdo...@gmail.com wrote:
 I think you can work around the problem using appender:
 auto buffer = appender!(int[])();

Yes, because it has a default argument which it passes to the Appender
constructor. If only we had default constructors for structs in D.. or
a general solution to this issue. I remember maybe a year ago or so
I've ran into the same issue with hashes, and now it almost bit me
hard again (luckily this was caught immediately in a failing
unittest).


Re: Passing Appender by value

2013-06-22 Thread Namespace

On Saturday, 22 June 2013 at 16:08:01 UTC, Andrej Mitrovic wrote:

On 6/22/13, monarch_dodra monarchdo...@gmail.com wrote:

I think you can work around the problem using appender:
auto buffer = appender!(int[])();


Yes, because it has a default argument which it passes to the 
Appender
constructor. If only we had default constructors for structs in 
D.. or
a general solution to this issue. I remember maybe a year ago 
or so
I've ran into the same issue with hashes, and now it almost bit 
me

hard again (luckily this was caught immediately in a failing
unittest).


What was the main reason for Walter to disable default CTors for 
structs?


Re: Passing Appender by value

2013-06-22 Thread monarch_dodra

On Saturday, 22 June 2013 at 16:31:16 UTC, Namespace wrote:
On Saturday, 22 June 2013 at 16:08:01 UTC, Andrej Mitrovic 
wrote:

On 6/22/13, monarch_dodra monarchdo...@gmail.com wrote:

I think you can work around the problem using appender:
auto buffer = appender!(int[])();


Yes, because it has a default argument which it passes to the 
Appender
constructor. If only we had default constructors for structs 
in D.. or
a general solution to this issue. I remember maybe a year ago 
or so
I've ran into the same issue with hashes, and now it almost 
bit me

hard again (luckily this was caught immediately in a failing
unittest).


What was the main reason for Walter to disable default CTors 
for structs?


So that *default* construction can be evaluated statically, which 
then means .init can exist, which allows all of D's postblit 
mechanics, as well as move semantics.


It also means that declaring statics in a function is possible 
and doesn't require any special run-time code for first 
initialization.


I think the problem is that since in C++ no-arg = default, 
they removed constructors that took no arguments, so as to avoid 
any confusion, or maybe they just didn't realize that someone 
might want to runtime construct something, but have no arguments 
to pass to the constructor.


IMO, there was a *little* bit of lack of hindsight on that one, 
but the choice was clearly superior to C++'s CC scheme on return 
by value...