View mode: basic / threaded / horizontal-split · Log in · Help
May 27, 2009
Struct d'tors and destructive assignment of return vals
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
Re: Struct d'tors and destructive assignment of return vals
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
Re: Struct d'tors and destructive assignment of return vals
== 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
Re: Struct d'tors and destructive assignment of return vals
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
Re: Struct d'tors and destructive assignment of return vals
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