Posted: Aug 13, 2010 7:06 am
by VazScep
Calilasseia wrote:I always understood the process of instantiating and de-instantiating objects to be performed by entities outside the objects in question. The new and delete operators achieve this. An object can contain within it a constructor method, which is used to tell the new operator how to initialise an object if the creation of an instance is accompanied by relevant initialisation data, and which the new operator calls after it has allocated memory for that object, set up the pointers to the methods, and provided a pointer to the object for the object reference variable to contain. In its simplest form, the delete operator simply returns the allocated memory to the operating system's free list, and sets the object reference variable to some suitable 'null' value to indicate that it's no longer pointing to an object.
The delete operator only exists in C++. Languages with garbage collection handle all memory management issues themselves. Setting an object's reference to a null value is only good for getting null-pointer dereferences, the behaviour of which as far as C++ is concerned could involve formatting your hard-drive. This isn't stability.

Removing oneself from a doubly-linked list is a very different operation to destroying oneself, so it should be a separate function. In a garbage-collected language, you would call this function explicitly, along with any other functions needed to free finite resources such as file-handles. If you want the small amount of automation that C++ gives you here in terms of automatically calling destructors of stack-allocated objects, you can use "with-open-file" constructs, which declare new objects whose resources are automatically released at the end of their scope, even if exceptions occur.

One big problem that needs to be addressed concerns garbage collection. In an environment where garbage collection is provided as an automatic feature of the run-time environment, problems can arise with respect to ensuring that destructors are called, if the programmer simply dereferences the entire list in one fell swoop, using the above doubly linked list example. indeed, there's an entire body of literature on the subject of garbage collection, because ensuring the consistent release of allocated resources (memory, file handles etc) is time consuming, and conflicts with the need to minimise the impact of the run-time environment's ancillary services upon the executing program.
Destructor issues don't occur in garbage-collected languages, because there generally aren't any destructors. Languages like Python, which uses a very simple reference-counting garbage-collector make destructors somewhat more useful, since the programmer can make strong guarantees about when destructors are called.

Balancing these requirements is one of those particularly difficult computer science problems, and finding a consistent, secure and fast garbage collection method is one of those Holy Grails of computer science that may never be achieved. All of which is compounded yet again when you consider programs that are multi-threaded, even if the threads are actually executed on one processor via the multitasking executive - it's possible, if you're not careful, for one thread to specify that it wants to delete an object at the same time as another thread wants to press that object into use, and synchronising usage versus deletion of objects across threads in a multitasking environment is another nice minefield for the unwary, made all the more hilarious when one implements multithreading on a genuine multiprocessor environment, where the threads are given their own processor to run on.
Finding such a Holy Grail was a goal a few decades ago. The only programmers still seriously worrying about garbage-collector efficiency are systems programmers and people working on embedded devices, who constitute a tiny fraction of all programmers. Garbage collected languages have been the norm for over a decade now. They make your code far safer (no more null-pointer dereferences) and massively boost programmer productivity. Requiring manual memory management everywhere is now just one big exercise in grossly premature optimisation --- most of your code doesn't doesn't need to be that fast, and the average programmer is as likely to do a worse job than the garbage collector would at freeing resources, certainly when it comes to safety. If you need better efficiency in that one tight function, you might just need a smart compiler that will do stack-allocations automatically, or a language which provides stack-allocation primitives (C#'s value types, Lisp's dynamic-extent declaration), or you just need to write your own memory pools.

newolder wrote:In my mind, self.trash takes the object in focus to the nearest waste receptacle. For example, the object in focus is a 1mm ball of steel in the hand before me. Self.trash causes magnet-like attraction whilst self.destroy makes the ball vanish. Am I way off?
I'm not sure. What languages are you familiar with? As Calilasseia said, objects are trashed in OOP languages by entities on the outside. Garbage-collecting languages deal with trash automatically, so this "taking out the trash" metaphor is pretty confused.

self.trash doesn't help you anymore than object.trash. "self" can't generally be used. The main point here is that trashing in the example has become a property of the object. Is that a reasonable assumption to make? Is trashing not equally a property of the trash-can? What about the cupboard under the sink? What about the person who carries the bag? Why is only the trash-bag given sole responsibility here, aside from the fact that Java insists on all verbs being owned by nouns? Do we not have a procedure here, something like:

person.acquireFrom(trashBag, sinkCupboard);
person.placeIn(trashBag, trashCan);

Now where do we put this procedure? Procedures in Javaland belong to nouns, so we need something like:

trashDisposalPlan.doIt(person, sinkCupboard, garbageCan)

Incidentally, "doIt" methods are common in Java. This is called the "Command Pattern", and is a great example of how OOP has been horribly confused by Java and the "Patterns Community" [*]. The Command Pattern is normally just a crude hack to simulate "first-class functions", which are not available in Java (they are now in C#), and which were always supported by Smalltalk and exploited pervasively.

[*] Design patterns have also been horribly confused by the "Patterns Community".