On 3/25/15 9:51 AM, Ali Çehreli wrote:
On 12/09/2014 08:53 AM, Steven Schveighoffer wrote:

 > On 12/9/14 11:17 AM, ketmar via Digitalmars-d-learn wrote:

 >> that file can be already finalized. please remember that `~this()` is
 >> more a finalizer than destructor, and it's called on *dead* object.

Agreed: D has a terminology issue here, what we call a "class
destructor" is a "class finalizer". I have added D to the Wikipedia
article:

   http://en.wikipedia.org/wiki/Finalizer

Now I want to improve some of my chapters.

 >> here this means that any other object in your object (including
 >> structs) can be already finalized at the time GC decides to call your
 >> finalizer.

Although I know the fact above, I think ketmar makes a distinction (that
is new to me) that a finalizer is a function that does not reference
class members but a destructor does (or safely can).

Think of it this way -- a D destructor can access data from it's own object. This means it CAN access its own members that are structs or value types. It should NOT access referenced data, unless that data is allocated outside the GC.

In Tango, there was a finalizer and a destructor. The finalizer was called from the GC. The destructor was called when using the 'delete' operator explicitly (and I think it also called the finalizer afterward). Having this informational structure helps to know where to put what cleanup code. I would love it if druntime added this feature, or something similar.


 > File is specially designed (although it's not perfect) to be able to
 > close in the GC. Its ref-counted payload is placed on the C heap to
 > allow access during finalization.
 >
 > That being said, you actually don't need to write the above in the class
 > finalizer, _file's destructor will automatically be called.
 >
 >> just avoid "destructors" unless you *really* need that. in your case
 >> simply let GC finalize your File, don't try to help GC. this is not C++
 >> (or any other language without GC) and "destructors" aren't destructing
 >> anything at all. "destructors" must clean up the things that GC cannot
 >> (malloc()'ed memory, for example), and nothing else.
 >>
 >
 > Good advice ;)
 >
 > I would say other than library writers, nobody should ever write a class
 > dtor.
 >
 > -Steve

Can somebody elaborate on that guideline please. Given a case where
runtime polymorphism is needed, so that we have to use classes, does the
guideline simply mean that "arrange for manual cleanup" or is there more
in that guideline? I am confused about the "library writers" part. :)

Destructors should only be used to clean non-GC resources (and in terms of completeness, you should implement such a destructor). It is important to remember that the GC may NEVER get around to calling your destructor. This means you cannot depend on it releasing non-GC resources in a timely manner.

A good example is a file descriptor. If you have an object that contains a file descriptor you SHOULD have a destructor which closes the file descriptor if not already closed. However, you should NOT technically rely on it being called in a timely manner. For cases where you can do it synchronously, use a specific method to close the file descriptor.

There is a school of thought that says it is an error to rely on the GC to destroy the FD, so why even have the destructor. But I see no reason to leak the FD out of spite.

This is why I say it should be only library writers -- they are the ones creating wrapper objects and using low level operations.

Of course, this isn't a hard and fast rule.

-Steve

Reply via email to