May 27, 2009
import std.stdio;

struct RC {
    uint N;

    this(this) {
        writeln("Postblit:  ", N);
    }

    ~this() {
        writeln("D'tor:  ", N);
    }
}

RC fun() {
    writeln("Doing stuff...");
    return RC(3);
}


void main() {
    RC foo = RC(1);
    writeln("Calling fun()...");
    foo = fun();
    writeln("Exiting...");
}

Output:

Calling fun()...
Doing stuff...
D'tor:  1
Exiting...
D'tor:  3

Would it be feasible to require that, when a struct is being destructively assigned the return value of a function, the d'tor is called for the old contents before the function that provides the return value is called instead of calling it after?  This would be useful, for example, for providing COW semantics when dealing with ranges whose elements are lazily constructed arrays:

struct SomeRange {
    T[] someArray;
    uint* nExternalReferences;  // to someArray.

    T[] popNext() {
        if(*nExternalReferences > 0) {
            someArray = someArray.dup;
            nExternalReferences = new uint;
        }

        // Modify someArray.
        return referenceCounted(someArray, nExternalReferences);
    }
}

Caller's end:

SomeRange s;
RefCounted r;
while(!s.empty) {
    // The underlying array will constantly be dup'd because
    // the d'tor for r is not being called until after popNext()
    // is called.
    r = s.popNext;
}
May 27, 2009
On Tue, 26 May 2009 21:20:41 -0400, dsimcha <dsimcha@yahoo.com> wrote:

> import std.stdio;
>
> struct RC {
>     uint N;
>
>     this(this) {
>         writeln("Postblit:  ", N);
>     }
>
>     ~this() {
>         writeln("D'tor:  ", N);
>     }
> }
>
> RC fun() {
>     writeln("Doing stuff...");
>     return RC(3);
> }
>
>
> void main() {
>     RC foo = RC(1);
>     writeln("Calling fun()...");
>     foo = fun();
>     writeln("Exiting...");
> }
>
> Output:
>
> Calling fun()...
> Doing stuff...
> D'tor:  1
> Exiting...
> D'tor:  3
>
> Would it be feasible to require that, when a struct is being destructively
> assigned the return value of a function, the d'tor is called for the old
> contents before the function that provides the return value is called instead
> of calling it after?

What if fun throws an exception?

-Steve
May 27, 2009
== Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> On Tue, 26 May 2009 21:20:41 -0400, dsimcha <dsimcha@yahoo.com> wrote:
> > import std.stdio;
> >
> > struct RC {
> >     uint N;
> >
> >     this(this) {
> >         writeln("Postblit:  ", N);
> >     }
> >
> >     ~this() {
> >         writeln("D'tor:  ", N);
> >     }
> > }
> >
> > RC fun() {
> >     writeln("Doing stuff...");
> >     return RC(3);
> > }
> >
> >
> > void main() {
> >     RC foo = RC(1);
> >     writeln("Calling fun()...");
> >     foo = fun();
> >     writeln("Exiting...");
> > }
> >
> > Output:
> >
> > Calling fun()...
> > Doing stuff...
> > D'tor:  1
> > Exiting...
> > D'tor:  3
> >
> > Would it be feasible to require that, when a struct is being
> > destructively
> > assigned the return value of a function, the d'tor is called for the old
> > contents before the function that provides the return value is called
> > instead
> > of calling it after?
> What if fun throws an exception?
> -Steve

Argh good point, didn't think of that.  Then I guess you're just screwed.  In that case, do you see any other way to get good COW semantics in this situation?
May 27, 2009
On Tue, 26 May 2009 21:44:51 -0400, dsimcha <dsimcha@yahoo.com> wrote:

> == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
>> What if fun throws an exception?
>> -Steve
>
> Argh good point, didn't think of that.  Then I guess you're just screwed.  In that
> case, do you see any other way to get good COW semantics in this situation?

opAssign maybe?  not sure...

-Steve
May 27, 2009
dsimcha wrote:
> == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
>> On Tue, 26 May 2009 21:20:41 -0400, dsimcha <dsimcha@yahoo.com> wrote:
>>> import std.stdio;
>>>
>>> struct RC {
>>>     uint N;
>>>
>>>     this(this) {
>>>         writeln("Postblit:  ", N);
>>>     }
>>>
>>>     ~this() {
>>>         writeln("D'tor:  ", N);
>>>     }
>>> }
>>>
>>> RC fun() {
>>>     writeln("Doing stuff...");
>>>     return RC(3);
>>> }
>>>
>>>
>>> void main() {
>>>     RC foo = RC(1);
>>>     writeln("Calling fun()...");
>>>     foo = fun();
>>>     writeln("Exiting...");
>>> }
>>>
>>> Output:
>>>
>>> Calling fun()...
>>> Doing stuff...
>>> D'tor:  1
>>> Exiting...
>>> D'tor:  3
>>>
>>> Would it be feasible to require that, when a struct is being
>>> destructively
>>> assigned the return value of a function, the d'tor is called for the old
>>> contents before the function that provides the return value is called
>>> instead
>>> of calling it after?
>> What if fun throws an exception?
>> -Steve
> 
> Argh good point, didn't think of that.  Then I guess you're just screwed.  In that
> case, do you see any other way to get good COW semantics in this situation?

This has been discussed by Bartosz, Walter, and myself quite a lot a couple of years ago. The solution we settled on was to always move the bits directly when a copy is the last access of the source (as is the case in your return expression). Walter hasn't implemented that yet.

Andrei
Top | Discussion index | About this forum | D home