Jump to page: 1 2
Thread overview
Question about RAII.
Jul 04, 2006
Peter C. Chapin
Jul 04, 2006
Derek Parnell
Jul 04, 2006
Oskar Linde
Jul 04, 2006
Peter C. Chapin
Jul 04, 2006
Derek Parnell
Jul 05, 2006
Bruno Medeiros
Jul 05, 2006
Derek Parnell
Jul 05, 2006
Bruno Medeiros
Jul 05, 2006
Sean Kelly
Jul 04, 2006
Robert.Atkinson
Jul 05, 2006
Walter Bright
Jul 05, 2006
Peter C. Chapin
Jul 06, 2006
Hasan Aljudy
July 04, 2006
Hello! I'm a C++ programmer who has started to look at D. I appreciate many of D's design decisions. However, I'm a little confused about how RAII is supported. It seems like it only semi-works. Consider the function below ('Example' is some class):

Example g()
{
  auto Example object1 = new Example;
  auto Example object2 = new Example;
  Example object3;

  if (f()) {
    object3 = object1;
  }
  else {
    object3 = object2;
  }
  return object3;
}

The idea is that I want to return one of two local objects depending on what f() returns. Assume f() interacts with the user so its return value can't be known to the compiler. The object that is not returned must be cleaned up. Assume that it holds resources other than memory that need to be released.

In the example above it looks like both object1 and object2 are destroyed and thus the returned reference is invalid. However, if I remove 'auto' from the local declarations than object1 and object2 don't get destroyed until garbage collection time... which is too late. It looks like I'm left with explicitly deleting the object that I don't return, but this is manual resource management and not RAII.

To make this example more concrete, suppose the class in question represents an on-screen window. Function g() lets the user select one of two newly created windows, returning the window selected and removing the other from the screen.

Thanks in advance for any comments.

Peter
July 04, 2006
On Tue, 04 Jul 2006 23:05:58 +1000, Peter C. Chapin <pchapin@sover.net> wrote:

> Hello! I'm a C++ programmer who has started to look at D. I appreciate
> many of D's design decisions. However, I'm a little confused about how
> RAII is supported. It seems like it only semi-works. Consider the
> function below ('Example' is some class):

The 'auto' in this context means "destroy the local member when it goes out of scope". This may or may not correlate to your RAII definition but that's what 'auto' means in D. It doesn't matter if the object is in use or not, if it goes out of scope it is destroyed. So in the situation you describe, you will be required to explictly delete the object you no longer want and do not use 'auto'.

Of course, another method is to only create the object when you know which one to create.

-- 
Derek Parnell
Melbourne, Australia
July 04, 2006
Peter C. Chapin wrote:
> Hello! I'm a C++ programmer who has started to look at D. I appreciate many of D's design decisions. However, I'm a little confused about how RAII is supported. It seems like it only semi-works. Consider the function below ('Example' is some class):
> 
> Example g()
> {
>   auto Example object1 = new Example;
>   auto Example object2 = new Example;
>   Example object3;
> 
>   if (f()) {
>     object3 = object1;
>   }
>   else {
>     object3 = object2;
>   }
>   return object3;
> }
> 
> The idea is that I want to return one of two local objects depending on what f() returns. Assume f() interacts with the user so its return value can't be known to the compiler. The object that is not returned must be cleaned up. Assume that it holds resources other than memory that need to be released.
> 
> In the example above it looks like both object1 and object2 are destroyed and thus the returned reference is invalid. However, if I remove 'auto' from the local declarations than object1 and object2 don't get destroyed until garbage collection time... which is too late. It looks like I'm left with explicitly deleting the object that I don't return, but this is manual resource management and not RAII.
> 
> To make this example more concrete, suppose the class in question represents an on-screen window. Function g() lets the user select one of two newly created windows, returning the window selected and removing the other from the screen.
> 
> Thanks in advance for any comments.
> 
> Peter

An auto referance such as those above is guaranteed to be destroyed at the end of the scope in which it is declared.  Returning such a referance is a no-no, as the object on the other side no longer exists when the function has ended!  (If you had directly returned object1 or object2, you should have gotten a compile-time error I believe.)

-- Chris Nicholson-Sauls
July 04, 2006
Peter C. Chapin skrev:
> Hello! I'm a C++ programmer who has started to look at D. I appreciate many of D's design decisions. However, I'm a little confused about how RAII is supported. It seems like it only semi-works. Consider the function below ('Example' is some class):
> 
> Example g()
> {
>   auto Example object1 = new Example;
>   auto Example object2 = new Example;
>   Example object3;
> 
>   if (f()) {
>     object3 = object1;
>   }
>   else {
>     object3 = object2;
>   }
>   return object3;
> }

It looks like you want some kind of transfer semantics. You can do that manually:

 if (f()) {
    object3 = object1;
    object1 = null;
  }
  else {
    object3 = object2;
    object2 = null;
  }

D lacks the necessary(*) provisions that would be needed to implement such behavior automatically. (like the c++ auto_ptr)

> In the example above it looks like both object1 and object2 are destroyed and thus the returned reference is invalid. However, if I remove 'auto' from the local declarations than object1 and object2 don't get destroyed until garbage collection time... which is too late. It looks like I'm left with explicitly deleting the object that I don't return, but this is manual resource management and not RAII.

The both raii variables have no way of knowing if other live references to the same object exists. They are not cleared when assigned to any other reference holding variable or passed to functions etc.

/Oskar

*) The obvious implementations would be a pointer wrapping struct, but for this D lacks:
- assignment operator (and possibly copy) overloading for structs
- destructors for structs
July 04, 2006
Everyone's already told you that returning an auto-reference is impossible as the reference gets destroyed by exiting the scope.

Couldn't the compiler detect this and throw an compile-error?  From simple inspection it seems to be a pretty easy addition to the compiler, the syntax is already quite clear.

In article <Xns97F65C90D676pchapinsovernet@63.105.9.61>, Peter C. Chapin says...
>
>Hello! I'm a C++ programmer who has started to look at D. I appreciate many of D's design decisions. However, I'm a little confused about how RAII is supported. It seems like it only semi-works. Consider the function below ('Example' is some class):
>
>Example g()
>{
>  auto Example object1 = new Example;
>  auto Example object2 = new Example;
>  Example object3;
>
>  if (f()) {
>    object3 = object1;
>  }
>  else {
>    object3 = object2;
>  }
>  return object3;
>}
>
>The idea is that I want to return one of two local objects depending on what f() returns. Assume f() interacts with the user so its return value can't be known to the compiler. The object that is not returned must be cleaned up. Assume that it holds resources other than memory that need to be released.
>
>In the example above it looks like both object1 and object2 are destroyed and thus the returned reference is invalid. However, if I remove 'auto' from the local declarations than object1 and object2 don't get destroyed until garbage collection time... which is too late. It looks like I'm left with explicitly deleting the object that I don't return, but this is manual resource management and not RAII.
>
>To make this example more concrete, suppose the class in question represents an on-screen window. Function g() lets the user select one of two newly created windows, returning the window selected and removing the other from the screen.
>
>Thanks in advance for any comments.
>
>Peter


July 04, 2006
Oskar Linde <oskar.lindeREM@OVEgmail.com> wrote in news:e8dqj5$29ns$1@digitaldaemon.com:

> It looks like you want some kind of transfer semantics. You can do that manually:
> 
>   if (f()) {
>      object3 = object1;
>      object1 = null;
>    }
>    else {
>      object3 = object2;
>      object2 = null;
>    }

That's a neat trick. Thanks. I can see that in many cases specifying which of the autos I don't want destroyed (in effect) would be easier than explicitly destroying everything else.

Peter
July 04, 2006
On Tue, 4 Jul 2006 17:35:55 +0000 (UTC), Peter C. Chapin wrote:

> Oskar Linde <oskar.lindeREM@OVEgmail.com> wrote in news:e8dqj5$29ns$1@digitaldaemon.com:
> 
>> It looks like you want some kind of transfer semantics. You can do that manually:
>> 
>>   if (f()) {
>>      object3 = object1;
>>      object1 = null;
>>    }
>>    else {
>>      object3 = object2;
>>      object2 = null;
>>    }
> 
> That's a neat trick. Thanks. I can see that in many cases specifying which of the autos I don't want destroyed (in effect) would be easier than explicitly destroying everything else.
> 
> Peter

Just checking, but doesn't setting an object reference to null just flag it as *available* for garbage collection, and isn't there no absolute guarantee that an object will actually be collected by the GC? In which case, you can't be certain that object1 or object2 will really have their destructor called. Whereas using the delete statement ensures the destructor call.

So I think that the code should be more like ...

   MyClass object1 = new MyClass( stuff1 );
   MyClass object2 = new MyClass( stuff2 );
   MyClass object3;

   if (f()) {
      object3 = object1;
      delete object2;
    }
    else {
      object3 = object2;
      delete object1;
    }

Though given this simplistic example I'd actually code it more like ...

   MyClass object3;

   if (f()) {
      object3 = new MyClass( stuff1 );
    }
    else {
      object3 = new MyClass( stuff2 );
    }

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
5/07/2006 9:24:10 AM
July 05, 2006
<Robert.Atkinson@NOSPAM.gmail.com.NOSPAM> wrote in message news:e8dtj3$2dc8$1@digitaldaemon.com...

> Couldn't the compiler detect this and throw an compile-error?  From simple
> inspection it seems to be a pretty easy addition to the compiler, the
> syntax is
> already quite clear.

You'll notice the auto reference is being assigned to a non-auto reference, which makes it all but impossible to detect.  What if it were stuck into an array?  What if the auto ref were passed into a function and then returned as non-auto?  What if..?

If you try to directly return an auto reference, the compiler will gladly whine:

class Foo{}

Foo foo()
{
 auto Foo f = new Foo;
 return f;
}

dtest.d(781): escaping reference to auto local f


July 05, 2006
Derek Parnell wrote:
> On Tue, 4 Jul 2006 17:35:55 +0000 (UTC), Peter C. Chapin wrote:
> 
>> Oskar Linde <oskar.lindeREM@OVEgmail.com> wrote in
>> news:e8dqj5$29ns$1@digitaldaemon.com: 
>>
>>> It looks like you want some kind of transfer semantics. You can do
>>> that manually:
>>>
>>>   if (f()) {
>>>      object3 = object1;
>>>      object1 = null;
>>>    }
>>>    else {
>>>      object3 = object2;
>>>      object2 = null;
>>>    }
>> That's a neat trick. Thanks. I can see that in many cases specifying which of the autos I don't want destroyed (in effect) would be easier than explicitly destroying everything else.
>>
>> Peter
> 
> Just checking, but doesn't setting an object reference to null just flag it
> as *available* for garbage collection, and isn't there no absolute
> guarantee that an object will actually be collected by the GC? In which
> case, you can't be certain that object1 or object2 will really have their
> destructor called. Whereas using the delete statement ensures the
> destructor call.
> 

I'm not sure if you're just asking that without regards to the previous code, you're if asking that because you may have misunderstood the previous code.
The point of setting those objects to null is not to collect it (if it was, indeed we couldn't be sure when the GC would collect), but indeed the opposite (to *prevent* collection). Because they are auto objects, the only to way to prevent (auto) collection is to setting them as null. Your example does work as well, of course.

> So I think that the code should be more like ...
> 
>    MyClass object1 = new MyClass( stuff1 );
>    MyClass object2 = new MyClass( stuff2 );
>    MyClass object3;
> 
>    if (f()) {
>       object3 = object1;
>       delete object2;
>     }
>     else {
>       object3 = object2;
>       delete object1;
>     }
> 
> Though given this simplistic example I'd actually code it more like ...
> 
>    MyClass object3;
> 
>    if (f()) {
>       object3 = new MyClass( stuff1 );
>     }
>     else {
>       object3 = new MyClass( stuff2 );
>     }
> 


-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 05, 2006
On Wed, 05 Jul 2006 01:36:54 +0100, Bruno Medeiros wrote:

> Derek Parnell wrote:
> 
> I'm not sure if you're just asking that without regards to the previous code, you're if asking that because you may have misunderstood the previous code.

Yep. I did misunderstand. My mistake, but I can see the 'trick' now. Is this method endorsed by Walter or is this just an artifact of the RAII implementation?

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
5/07/2006 10:43:07 AM
« First   ‹ Prev
1 2