Destructor semantics

Steven Schveighoffer schveiguy at yahoo.com
Thu Aug 12 04:44:26 PDT 2010


On Wed, 11 Aug 2010 16:14:56 -0400, Don <nospam at nospam.com> wrote:

> Michel Fortin wrote:
>> On 2010-08-11 15:09:45 -0400, Jonathan M Davis <jmdavisprog at gmail.com>  
>> said:
>>
>>> On Wednesday, August 11, 2010 11:33:54 Michel Fortin wrote:
>>>> I'm not too sure that'll work very well. I think a better solution
>>>> would be to have a way to distinguish between a struct that can be put
>>>> on the GC heap and one that cannot. A struct that cannot go on the GC
>>>> heap make it safe to access GC-managed members in its destructor, and
>>>> thus can have a @safe destructor.
>>>
>>> But couldn't the fact that a struct has a destructor make it so that  
>>> it can't be
>>> declared anywhere but on the heap? The destructor itself could be what
>>> distinguishes them. I don't see a need for any other @attributes or  
>>> whatnot to
>>> distinguish them.
>>  Sure, and now you can't use std.containers.Array as a member in a  
>> Class, neither std.stdio.File, etc. Is there something left classes can  
>> do?
>
> As far as I can tell, the use cases for finalizers are very limited. To  
> me, destructors don't make any sense unless they are deterministic.
> For example, I think having a File class is probably a bug. You may be  
> on a system which has no limit on the number of file handles, but  
> generally, if you need resource management, you need a guarantee that  
> the destructor will be called.
>
> If a file handle is stored as part of a class, with a destructor that  
> closes the file, the file might never get closed. So I don't think it's  
> unreasonable to say that a struct with a destructor cannot be a member  
> of a class.

So classes are not allowed to have open files?  That's too limited.   
Deterministic closing of the file is still possible, just not guaranteed.

Here's the thing, we shouldn't be preventing smart people from writing  
useful code because we can't think of a way to make sure all idiot  
programmers close all their resources.  Note also that a resource leak is  
not as damaging as memory corruption, which we have somewhat of an  
obligation to try and prevent idiots from doing.

>
> Personally I think destructors should be restricted to structs and scope  
> classes. I suspect that some form of registration with the gc could do  
> the job of finalizers.
>
> Destructor <=> deterministic destruction.

Destructors as they are now are too limited, because they cannot be sure  
they are being called by the GC or not, they must assume so.  So in one  
sense I agree with you.  But in another sense, we *still* need a way to  
clean up non-GC resources from GC-allocated items.  Preventing GC  
allocated items from holding non-GC resources is a step in a very wrong  
direction.

I think any one of the proposals here that separates finalizers from  
destructors should be adequate.  My backwards-compatible one is to pass a  
parameter to the destructor indicating whether it's being called  
deterministically or not, but that doesn't lend itself to preventing @safe  
finalizers.  Michael also has one for using ~~this() and ~this().  We  
could designate a method that clear uses, like dispose() that  
deterministically disposes all resources.  I don't really like the  
interface solution, because looking up an interface is expensive, plus  
clear is a template so it doesn't need to use interfaces.

Whatever gets decided, I don't think anything should prevent them from  
being GC allocated, it's just too limiting for useful code.  The one  
initiative the compiler could take is to prevent writing a finalizer in  
@safe code, since that can lead to memory corruption.

-Steve


More information about the Digitalmars-d mailing list