On Thursday, 1 May 2014 at 15:28:25 UTC, Andrei Alexandrescu
wrote:
On 5/1/14, 7:30 AM, H. S. Teoh via Digitalmars-d wrote:
On Thu, May 01, 2014 at 01:37:28AM -0700, Jonathan M Davis via
Digitalmars-d wrote:
While it's not good to rely on finalizers, they're good to
have as
backup if the appropriate cleanup function doesn't get called
like
it's supposed to. They're not as critical as they'd be in
Java, since
we have structs, but I'd be disinclined to remove finalizers
from D
without a really good reason.
[...]
I'd like to hear an enumeration of those reasons as well.
1. Most scarce resources must be released eagerly. GC
collections occur relatively rarely and are triggered by
different signals (low on memory).
2. The notion of running the GC when one runs out of file
handles or sockets is terribly inefficient.
3. Destructors are odd - they will run in a different thread
than the one that created the object. They also are limited in
surprising ways, i.e. may not allocate memory or block on other
threads directly or indirectly.
4. Due to imprecision, there's no actual guarantee any given
destructor will end up running. Leaving a scarce resources at
the whim of a best-effort approach is poor design.
These are good arguments against destructors for GC managed
objects, IMO.
But conceptually, this is _not_ the same as classes! As others
have mentioned, it's possible to created structs with `new`, or
have them in dynamic arrays, as well as managing class objects
manually.
Maybe the language should have some way to distinguish between
GC-managed and manually-managed objects, preferably in the type
system. Then it could be statically checked whether an object is
supposed to be GC-managed, and consequentially shouldn't have a
destructor.
The difference between classes and structs should then be
reference vs. value semantics, and polymorphic vs static (which
correlate nicely). It should, however, not imply whether the
object is managed by the GC or not. Some kind of ownership
mechanism would be more suited for that.