digitalmars.D - Question about RAII.
- "Peter C. Chapin" <pchapin sover.net> Jul 04 2006
- "Derek Parnell" <derek psych.ward> Jul 04 2006
- Chris Nicholson-Sauls <ibisbasenji gmail.com> Jul 04 2006
- Oskar Linde <oskar.lindeREM OVEgmail.com> Jul 04 2006
- "Peter C. Chapin" <pchapin sover.net> Jul 04 2006
- Derek Parnell <derek nomail.afraid.org> Jul 04 2006
- Bruno Medeiros <brunodomedeirosATgmail SPAM.com> Jul 04 2006
- Derek Parnell <derek nomail.afraid.org> Jul 04 2006
- Bruno Medeiros <brunodomedeirosATgmail SPAM.com> Jul 05 2006
- Sean Kelly <sean f4.ca> Jul 05 2006
- Robert.Atkinson NOSPAM.gmail.com.NOSPAM Jul 04 2006
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 04 2006
- Walter Bright <newshound digitalmars.com> Jul 04 2006
- "Peter C. Chapin" <pchapin sover.net> Jul 05 2006
- Hasan Aljudy <hasan.aljudy gmail.com> Jul 05 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
Jul 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
Jul 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
Jul 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
Jul 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
Jul 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
Jul 04 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; }
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
Jul 04 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
Jul 04 2006
Derek Parnell wrote: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?
Well, actually, now that I recall the spec, that behavior isn't valid: "Assignment to an auto, other than initialization, is not allowed." But since the auto mechanism is under consideration to have some changes, the future behavior might be different and allow something like this. Or not at all. For instance, if we have an auto that instead of being applied to variables, is applied to values, like this: auto Bar(); Foo foo = auto Foo(); then how would one cancel the Foo() destruction? A new mechanism would be required, but then it might become a little awkward. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jul 05 2006
Derek Parnell wrote: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?
The latter I think. Walter has said in the past that the compiler is free to allocate auto variables on the stack, it just isn't required. Sean
Jul 05 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
Jul 04 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
Jul 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.
The reason the example "works" in C++ is not because RAII is any different in D - in D, as well as C++, both object1 and object2 get destroyed at the end of the return. What happens in C++ is the: object3 = object1; makes a *copy* of object1 via the default (or explicit) copy constructor. In D, just a reference to object1's instance is copied. You can make the D version behave like the C++ one as follows: Example g() { auto Example object1 = new Example; auto Example object2 = new Example; Example object3; if (f()) { object3 = new Example(object1); } else { object3 = new Example(object2); } return object3; } and then in the definition of Example, add the constructor: this(Example e) { ...copy members... } To explicitly run the destructor on an object, use: delete object1;
Jul 04 2006
Walter Bright <newshound digitalmars.com> wrote in news:e8f9b7$17u2$1 digitaldaemon.com:You can make the D version behave like the C++ one as follows: Example g() { auto Example object1 = new Example; auto Example object2 = new Example; Example object3; if (f()) { object3 = new Example(object1); } else { object3 = new Example(object2); } return object3; }
I see what you are saying. Thanks, that is helpful. Peter
Jul 05 2006
Peter C. Chapin wrote: <snip>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. Peter
I always had the impression that RAII indeed *is* manual resource management.
Jul 05 2006









"Derek Parnell" <derek psych.ward> 