D - Destructors
- Kent Quirk (48/48) Jan 14 2003 I'm a bit twisted around on the destructor thing.
- Burton Radons (10/15) Jan 14 2003 The RAII vernacular means nothing to me, and I don't know what baggage
- Kent Quirk (12/19) Jan 14 2003 Perfect. That neatly handles my worries.
- Burton Radons (52/72) Jan 14 2003 Ah, so it's pretty much tied into C++'s constructor/destructor model,
- Russell Lewis (5/7) Jan 14 2003 Welcome, Kent. Good to see the MindRover folks are reading about D,
I'm a bit twisted around on the destructor thing. The docs say this about destructors: "The garbage collector calls the destructor function when the object is deleted. " ... "The program can explicitly inform the garbage collector that an object is no longer referred to (with the delete expression), and then the garbage collector calls the destructor immediately, and adds the object's memory to the free storage. The destructor is guaranteed to never be called twice." This statement on destructors is far stronger than Java's finalize(), which basically says "we might get around to calling it, maybe, if we feel like it, but don't count on it." Which is worse than useless, as far as I'm concerned. Better not to have it at all. Question 1: It's not absolutely clear: does D guarantee that destructors will always eventually be called, even on program termination? (Please say yes!) Question 2: The introduction explicitly refers to enabling the RAII (Resource Acquisition Is Initialization) idiom from C++. To me, that says "acquire your resources in the constructor, free them in the destructor." That, in turn, enables a very useful idiom in C++, which is instantiating a class to acquire a valuable resource that is then freed automatically when the object is deleted. For example, a lock on a file: : void writeToLog(string message) : { : FileLock theLock(LOGFILE); // this acquires the lock on the log file : writeToLog(LOGFILE, message); // log file lock automatically released when we exit the routine // ...even if we throw } The nice thing about this is that we don't have to remember to explicitly release the lock. In general, this idiom allows you to avoid a common programming error of forgetting to make corresponding edits. Now it seems that in D, I could write the same code...but I wouldn't know when the lock would be released. It might even seem to work properly under testing but fail under strange conditions when the GC didn't run for a while. Looks like the corresponding D idiom would require that I explicitly delete the lock in a finally clause. Which gets into the whole "I have to remember to maintain both halves of the code" thing. Which, IMO, weakens the RIAA model considerably. In the docs there's a statement: 'Which of "release resource using destructor" (C++) or "release resource using finally" (D) is better is a topic for much debate, but I obviously am in the latter camp. ' So clearly this was not only a deliberate design decision, but one based on superiority. Please enlighten me. I understand the argument that "deterministic GC based on objects going out of scope is Really Really Hard to do reliably". But I have never before heard anyone argue that the lack of deterministic destruction is A Good Idea. Why is it better to be forced to do things twice? -- Kent CTO, CogniToy
Jan 14 2003
Kent Quirk wrote:Question 1: It's not absolutely clear: does D guarantee that destructors will always eventually be called, even on program termination? (Please say yes!)No. But I don't see any reason why that shouldn't be a requirement.Question 2: The introduction explicitly refers to enabling the RAII (Resource Acquisition Is Initialization) idiom from C++. To me, that says "acquire your resources in the constructor, free them in the destructor."The RAII vernacular means nothing to me, and I don't know what baggage the acronym brings along. What D does here is allow you to automatically delete a class instance in a local variable when its scope exits. You apply the "auto" keyword to a class as well as definitions of it in the scope, so: auto class FileLock ... auto FileLock theLock = new FileLock (LOGFILE); We have the synchronized statement as well.
Jan 14 2003
In article <b01bgr$16ui$1 digitaldaemon.com>, Burton Radons says...The RAII vernacular means nothing to me, and I don't know what baggage the acronym brings along. What D does here is allow you to automatically delete a class instance in a local variable when its scope exits. You apply the "auto" keyword to a class as well as definitions of it in the scope, so: auto class FileLock ... auto FileLock theLock = new FileLock (LOGFILE);Perfect. That neatly handles my worries. RAII (Resource Acquisition Is Initialization) is an idiom that says anytime you need a resource, you should do it as the initialization portion of an object designed to hold the resource. Then you free the resource on the destructor of that object. Then you can use object lifetime as a way of managing a resource. It's a way of avoiding ever having dangling pointers. Since I adopted it, I almost never use "raw" pointers and I almost never have null pointer or dangling pointer bugs. Kent Quirk CTO, CogniToy
Jan 14 2003
Kent Quirk wrote:In article <b01bgr$16ui$1 digitaldaemon.com>, Burton Radons says...Ah, so it's pretty much tied into C++'s constructor/destructor model, the problem with which is that it makes exceptions too expensive. I don't think I've seen C++ code which uses exceptions, in fact. There's restrictions with auto objects. They can't be put into fields or globals, or reassigned. I think this is a plus, as it means that the destructor is called in a stable environment, as opposed to the burning house a GC destructor runs in. The standard should have big caution signs around the documentation on destructors - I've burnt myself with them a couple times now. For example (and off-topic from here on out), if destructors are called on all objects at the end of the program, then deregistration where you take yourself out of a global dictionary might break down if it has been freed already. But there's a solution to the problem: put code that deletes all entries in the list, or simply empty it if that is enough, in the static destructor, effectively ordering destruction. class Control { static Control [HWND] map; Control [] children; this (Control parent) { if (parent) parent.children ~= this; hwnd = CreateWindow (...); map [hwnd] = this; } ~this () { delete map [hwnd]; /* If map has already been deleted by the GC at the end of the program, this will segfault. */ } static ~this () { map = null; } } Whether merely assigning the static list to null is good enough depends upon what happens in the destructor. Notice that I've defined a completely different GC environment: controls are NOT collected unless if they are explicitly deleted because of their global registration. This means that any objects, such as the children list, are not deleted by the time we get to the destructor normally, so it's spared from normal GC destructors' chaotic environment. But after the static destructors have been executed, the controls will be collected in random order, which can lead to hard to figure out bugs. So I do need to delete the list manually in my case: static ~this () { while (map.length) delete map.values [0]; }The RAII vernacular means nothing to me, and I don't know what baggage the acronym brings along. What D does here is allow you to automatically delete a class instance in a local variable when its scope exits. You apply the "auto" keyword to a class as well as definitions of it in the scope, so: auto class FileLock ... auto FileLock theLock = new FileLock (LOGFILE);Perfect. That neatly handles my worries. RAII (Resource Acquisition Is Initialization) is an idiom that says anytime you need a resource, you should do it as the initialization portion of an object designed to hold the resource. Then you free the resource on the destructor of that object. Then you can use object lifetime as a way of managing a resource.
Jan 14 2003
-- Kent CTO, CogniToyWelcome, Kent. Good to see the MindRover folks are reading about D, too! I loved that game! The visual programming model was intriguing. I never actually even looked at ICE, though. For all the programmers listening here, MindRover is definitely a game worth looking into :)
Jan 14 2003