On Thu, 01 May 2014 00:07:42 -0400, Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote:

On 4/30/14, 7:20 PM, Steven Schveighoffer wrote:
On Wed, 30 Apr 2014 21:51:38 -0400, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:

On 4/30/14, 6:04 PM, Steven Schveighoffer wrote:
destructors are for cleaning up non-GC resources. File handles, malloc'd
memory, etc. I don't see why these need to be eliminated.

Virtually all GCs are known to be horrible at managing scarce
resources (including memory itself).

The destructor can be a crutch, but it's not good to leave open
resources when the user of your code has not cleaned them up manually.

Sounds like defensive programming to me.

Not at all. I've written programs that run for weeks at a time without ever crashing, who continually manage such resources via the GC.

If the GC cleans up your object, but your object wasn't finalized, you would have to make that a hard error. i.e. crash.

Still not talked about that I have seen, is the fact that with RC, we need a solution for cycles. If that's the GC then the GC WILL be cleaning up objects, even if they are ref counted.

I can see no reason to disallow destruction from cleaning up resources
that nobody else has managed to clean up.

Make memory management faster and better for everyone. I'm not saying it's reason enough, but it's a reason.

It doesn't make it better. The GC still is cleaning up the memory. Having it call close(fd) doesn't delay or make worse anything.

The largest problem with D destructors comes from trying to clean up D
objects in destructors of structs, that you never expected to be done
via the GC.

Cleaning up files and malloc'd memory is not an issue.

Not getting this...

class C
{
   private int fd = -1;
   private ubyte[] buffer;
   this(string fname) {
      fd = open(fname, O_CREAT);
      buffer = (cast(ubyte*).malloc(100))[0..100];
   }

   ~this() {
      if(fd != -1) { close(fd); fd = -1;}
      if(buffer.ptr) { .free(buffer.ptr); buffer = null}
   }
}

There is no problem with this code. It works correctly in all cases. It's not inefficient. It's not cumbersome or awkward or confusing. It's exactly what class destructors are for.

However, this *is* a problem:

class C
{
   RCValue s;
}

I have no way to say how s will be destructed, unless I poison it somehow. Even still, s.~this() will be called when C.~this() is done. This can be run in a separate thread as another object that is calling s.~this() at the same time.

Removing ~this() for classes just ADDS complication that we don't need. You are trying to fix the problem for the second situation by introducing a problem for the first that is unnecessary.

Solutions for the second problem are not predicated on jettisoning class dtors. You can, for instance, try and run the dtor for the instance of C in the same thread where it is owned. You could, as you say, force C into a ref counted mechanism. But this doesn't mean you should prevent C from cleaning up its resources!

Please understand that I'm not arguing for the status quo. What I'm arguing is that class destructors DO have some valid uses, and removing them would introduce new problems. I agree we need to find a solution to the ref counting + GC problem.

-Steve

Reply via email to