Thread overview
Postblit isn't called on rvalue return
Apr 24, 2013
Sebastian Graf
Apr 24, 2013
Ali Çehreli
Apr 24, 2013
Sebastian Graf
Apr 24, 2013
Ali Çehreli
Apr 25, 2013
Sebastian Graf
April 24, 2013
For this program:

    import std.stdio;

    struct S
    {
        ubyte* b;
        ubyte buf[128];

        this(this)
        {
            writeln("postblit");
        }
    }

    auto ref makeS()
    {
        S s;
        s.b = s.buf;
        writeln("made S at ", cast(void*)&s, ", s.b == ", s.b);
        return s;
    }

    void main()
    {
        S s = makeS();
        writeln("got back S at ", cast(void*)&s, ", s.b == ", s.b);
    }

I get

    made S at 18FC64, s.b == 18FC68
    got back S at 18FCF4, s.b == 18FC68

as output for dmd 2.062. Patching s.b to point into the newly allocated struct in postblit is crucial here, but it seems like the postblit constructor isn't called, nor is there any attempt to optimize away the temporary in `makeS()` even with -O.
Is this is a bug or am I doing something wrong?
April 24, 2013
On Wednesday, 24 April 2013 at 11:42:01 UTC, Sebastian Graf wrote:
> For this program:
>
>     import std.stdio;
>
>     struct S
>     {
>         ubyte* b;
>         ubyte buf[128];
>
>         this(this)
>         {
>             writeln("postblit");
>         }
>     }
>
>     auto ref makeS()
>     {
>         S s;
>         s.b = s.buf;
>         writeln("made S at ", cast(void*)&s, ", s.b == ", s.b);
>         return s;
>     }
>
>     void main()
>     {
>         S s = makeS();
>         writeln("got back S at ", cast(void*)&s, ", s.b == ", s.b);
>     }
>
> I get
>
>     made S at 18FC64, s.b == 18FC68
>     got back S at 18FCF4, s.b == 18FC68
>
> as output for dmd 2.062. Patching s.b to point into the newly allocated struct in postblit is crucial here, but it seems like the postblit constructor isn't called, nor is there any attempt to optimize away the temporary in `makeS()` even with -O.
> Is this is a bug or am I doing something wrong?

First, as the local 's' in makeS() is local, it cannot be returned by ref. So, the 'auto ref' return type of makeS() becomes by-value.

However, rvalues are never copied in D. The compiler automatically moves the bits of the rvalue to the left-hand side object, and to be correct, it also elides the destructor execution on the rvalue. (Note that this is not the RVO and NRVO optimization that C++ "allows". This is a language feature in D.)

For that feature to be available at all, struct objects must not have references to themselves; D explicitly makes it illegal.

So, unfortunately your S is not a valid type in D because of the following line (.ptr is added by me):

    s.b = s.buf.ptr;

Ali
April 24, 2013
On Wednesday, 24 April 2013 at 20:53:11 UTC, Ali Çehreli wrote:
>
> First, as the local 's' in makeS() is local, it cannot be returned by ref. So, the 'auto ref' return type of makeS() becomes by-value.
>
> However, rvalues are never copied in D. The compiler automatically moves the bits of the rvalue to the left-hand side object, and to be correct, it also elides the destructor execution on the rvalue. (Note that this is not the RVO and NRVO optimization that C++ "allows". This is a language feature in D.)
>
> For that feature to be available at all, struct objects must not have references to themselves; D explicitly makes it illegal.
>
> So, unfortunately your S is not a valid type in D because of the following line (.ptr is added by me):
>
>     s.b = s.buf.ptr;
>
> Ali

Thanks, this explains a lot. I was interfacing with a C library when tracing back an error to this. I eagerly submitted a Bug report http://d.puremagic.com/issues/show_bug.cgi?id=9985. Seems to me that dmd doesn't do NRVO (?), see the issue.
April 24, 2013
On Wednesday, 24 April 2013 at 21:36:48 UTC, Sebastian Graf wrote:

> Seems to me that dmd doesn't do NRVO (?), see the issue.

I can see that NRVO would be faster than the extra bit-copy.

Especially the last one of the following set of blog posts is relevant. The posts explain the rationale for this design decision (I don't remember whether they provide an exact answer to your question):

http://bartoszmilewski.com/2008/10/18/who-ordered-rvalue-references-part-1/

http://bartoszmilewski.com/2008/10/26/who-ordered-rvalue-references-part-2/

http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/

Ali
April 25, 2013
On Wednesday, 24 April 2013 at 22:29:55 UTC, Ali Çehreli wrote:
> On Wednesday, 24 April 2013 at 21:36:48 UTC, Sebastian Graf wrote:
>
>> Seems to me that dmd doesn't do NRVO (?), see the issue.
>
> I can see that NRVO would be faster than the extra bit-copy.
>
> Especially the last one of the following set of blog posts is relevant. The posts explain the rationale for this design decision (I don't remember whether they provide an exact answer to your question):
>
> http://bartoszmilewski.com/2008/10/18/who-ordered-rvalue-references-part-1/
>
> http://bartoszmilewski.com/2008/10/26/who-ordered-rvalue-references-part-2/
>
> http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/
>
> Ali

They did. Thanks for this awesome read :)