August 25, 2004
"pragma" <pragma_member@pathlink.com> wrote in message news:cgif07$29ev$1@digitaldaemon.com...
> In article <cgia4c$273m$1@digitaldaemon.com>, Ben Hinkle says...
> >
> >
> >> Honestly, my expectation was that during the final collection (before
> >program
> >> exit) all the finalizers would be run *first* before any memory is
freed.
> >
> >That makes sense - though it would cause two loops over the garbage
instead
> >of one. Also no-one has brought up the cases when garbage can be brought back to life. That's one reason why Java's finalizers are frowned upon - they can bring back dead references and generally cause the GC to jump through hoops to make sure it isn't cleaning up live data.
>
> I see what you mean.  Granted, there's nothing keeping a destructor from creating *more* data on the heap in a growing spiral of allocations.  But
I
> really don't see that as any more a problem as infinite recursion or mutually-referenced functions (like in the invariant 'bug' menioned
earlier in
> this NG).  But I strongly feel that reducing destructors to playing with
only
> scalar types (as we've discovered that object references are all "weak" in
the
> present D implementation during the final collect) reduces their
capability to
> near uselessness.

Destructors should only be used to release external resources - like file
handles, malloc'ed memory etc. To quote from the D documentation on the
section about destructors:
<quote>
When the garbage collector calls a destructor for an object of a class that
has members that are references to garbage collected objects, those
references are no longer valid. This means that destructors cannot reference
sub objects. This rule does not apply to auto objects or objects deleted
with the DeleteExpression.
The garbage collector is not guaranteed to run the destructor for all
unreferenced objects. Furthermore, the order in which the garbage collector
calls destructors for unreference objects is not specified.
<\quote>

It would be nice if we lived in a world where the GC could be fast and run destructors "nicely" but given the choice I would go for GC performance. Destructors should be a very weak construct. You never know when or if they will run so most of the time relying on them is a bug in disguise. Google around for web pages about Finalizers and Java and you'll get an idea how everyone in the Java world says not to use them. Remember all this destructor running happens on every GC pass, not just program exit.

> I also just noticed that my pseudocode on the previous post was also a
little
> flawed, and hence misleading.  If one were to loop over a /copy/ of the
current
> set of finalizers, after clearing out the old list, the outer loop stands
a good
> chance of actually terminating.
>
> >What if one of
> >the destructors assigns a reference to some garbage to a static variable
and
> >thus brings it back to life? The GC needs to check all the program's references after the destructors are run to make sure no garbage was
brought
> >to life. That would be a nasty performance hit.
>
> Well, "ressurecting" an object properly would require the GC to register
that
> object's finalizer, in which case it looks like a normal object.  That
/would/
> thwart the present behavior as well as my informal proposal in my previous
post.
>
> Personally, I'd rather have all my objects a /chance/ of cleaning up
propertly
> on program exit rather than have unpredictable behavior inside of
destructors.
> I know what I'm asking for is deterministic destruction of objects, in all cases, which has been something of a holy war on the D NG.
>
> I think its possible to finialize in the proposed method and abort to a
full
> free of the heap if the loop runs for too long, or if there's no change in
the
> number of finalizers for a number of iterations.  At least that way, you
have
> given the program a fighting chance of being well behaved on exit without bending over backwards in your code.
>
> Another way to go would be to allow the GC to track a set of privileged references that are guaranteed to be finalized before a dealloc on exit.
These
> would be explicitly set in the client code and would be understood to
delay
> program termination by ever so much.
>
> At the very least, it'd be nice to have a way to check if a reference is
still
> valid, and hasn't been collected.  That way one could treat object
references as
> 'weak' if you're using code inside of a destructor.
>
> -Pragma
> [[ EricAnderton at (let my objects go) yahoo.com ]]


August 25, 2004
In article <cgguse$1jab$1@digitaldaemon.com>, antiAlias says...
>
>Yes, that would be helpful. But it's not /always/ practical to avoid touching other objects during destruction, though perhaps 'desirable'.

I bet this works:

void main(){
auto Bar b = new Bar();
auto Foo f = new Foo();
b.event = &(f.notify);
}

>And it's not an obvious error either, since one could hardly be blamed for thinking the delegate holds a reference to its enclosing class instance (it's a delegate; not a function). If so, then the instance should still be live as long as the delegate is referenced ... yes? Apparently that's not how it works. Sure looks like a bug.

The problem is that once execution has left main(), all bets are off.  So what's happening here is that the references to Foo and Bar are being lost when main() exits and then the gc is run.  I imagine more common problems with this might possibly be addressed by having the gc make multiple passes on application exit, but I have a feeling that this would be shaky at best.  I have no problem with objects referencing other objects on destruction, but the user should be aware that this is unreliable in this particular situation.


Sean


August 25, 2004
In article <cgisdb$2g83$1@digitaldaemon.com>, Ben Hinkle says...
>
>Destructors should only be used to release external resources - like file
>handles, malloc'ed memory etc. To quote from the D documentation on the
>section about destructors:
><quote>
>When the garbage collector calls a destructor for an object of a class that
>has members that are references to garbage collected objects, those
>references are no longer valid. This means that destructors cannot reference
>sub objects. This rule does not apply to auto objects or objects deleted
>with the DeleteExpression.
>The garbage collector is not guaranteed to run the destructor for all
>unreferenced objects. Furthermore, the order in which the garbage collector
>calls destructors for unreference objects is not specified.
><\quote>

Yikes.  All apologies to Walter, who has very kindly saved me the embarassment of being told this from himself.

I guess that says it.  Its not a bug, just not at all what I expected.  All the same, I'd like to request that this be seriously reconsidered for V2.0.

So I suppose the proper "D" way to proceed is to use an auto object on the "main" thread, that manages critical resources for me?

>
>It would be nice if we lived in a world where the GC could be fast and run destructors "nicely" but given the choice I would go for GC performance. Destructors should be a very weak construct. You never know when or if they will run so most of the time relying on them is a bug in disguise. Google around for web pages about Finalizers and Java and you'll get an idea how everyone in the Java world says not to use them. Remember all this destructor running happens on every GC pass, not just program exit.

I see what you mean.  Having developers code destructors in this fashion can have the consequence of increased performance.  I still contend that D supporting "strong" constructors changes little but D's flexibility.

Thanks everybody (Ben, Kris, Sean) for their help here on this issue.  Again, all apologies to Walter for my having wasted his time with something that was in the documentation.

- Pragma
[[ EricAnderton at (auto + deamon = fix?) yahoo.com ]]
August 26, 2004
> Thanks everybody (Ben, Kris, Sean) for their help here on this issue. Again, all apologies to Walter for my having wasted his time with something that was in the documentation.

Actually I hadn't read that part of the doc until today either. My eariler post when I was messing with std.stream was trying to do too much in destructors so you're definitely not alone in writing ambitious destructors. Maybe if that part of the doc was in bold and blinking or something... It's very easy to just think destructors are just like C++ destructors only you don't have to worry about freeing memory. oh boy is that dangerous.
August 26, 2004
In article <cgj8qb$2ler$1@digitaldaemon.com>, pragma says...

>>The garbage collector is not guaranteed to run the destructor for all unreferenced objects.

Please see THIS POST from Walter, and the discussion before and after it: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/3488

In particular, Walter said: "I must have misspoke, because when the gc collects an object, it *does* run the destructor." (Walter's emphasis on *does*).

I have security apps planned which rely on Walter's statement being true. Where is this "not guaranteed" quote in the manual? I couldn't find it. Basically - help! Who's right? Walter, or the manual? Walter, please could you clarify (again), and fix the manual if it's wrong.

Jill


August 26, 2004
"antiAlias" <fu@bar.com> wrote in message news:cgipm8$2f1j$1@digitaldaemon.com...
> > Well let's not jump to conclusions... I would like to contend that this
> seems
> > like a mistake in implementation and is still likely a "bug" until proven otherwise. :)
>
> Fair point Eric. Having come-a-cropper over so many fundamental "no ... surely not!" type issues, I'm afraid my resilience against more of same has been frayed to tatters. Part of the whole "library development issues: what to do?" thread.

LOL!

Shared, pain, old buddy. But fear not, you have several weeks while Phoenix founders before you must face reality.

Or, optimistically, it might actually succeed, in which case we'll all be happy. :)

>
> > All I want is to write good software in D, and through that have D
> succeed.
>
> Hear hear. There's no other reason why I've spent four months 80-hours a week on Mango. Unfortunately, it sometimes feels as though the language, and /particularly/ the maturation 'process' behind it, is actually working against that goal (note that the "what to do?" thread all but disappeared down the black-hole). More's the pity.
>
>


August 26, 2004
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:cgisdb$2g83$1@digitaldaemon.com...
>
> "pragma" <pragma_member@pathlink.com> wrote in message news:cgif07$29ev$1@digitaldaemon.com...
> > In article <cgia4c$273m$1@digitaldaemon.com>, Ben Hinkle says...
> > >
> > >
> > >> Honestly, my expectation was that during the final collection (before
> > >program
> > >> exit) all the finalizers would be run *first* before any memory is
> freed.
> > >
> > >That makes sense - though it would cause two loops over the garbage
> instead
> > >of one. Also no-one has brought up the cases when garbage can be brought back to life. That's one reason why Java's finalizers are frowned upon - they can bring back dead references and generally cause the GC to jump through hoops to make sure it isn't cleaning up live data.
> >
> > I see what you mean.  Granted, there's nothing keeping a destructor from creating *more* data on the heap in a growing spiral of allocations.  But
> I
> > really don't see that as any more a problem as infinite recursion or mutually-referenced functions (like in the invariant 'bug' menioned
> earlier in
> > this NG).  But I strongly feel that reducing destructors to playing with
> only
> > scalar types (as we've discovered that object references are all "weak" in
> the
> > present D implementation during the final collect) reduces their
> capability to
> > near uselessness.
>
> Destructors should only be used to release external resources - like file
> handles, malloc'ed memory etc. To quote from the D documentation on the
> section about destructors:
> <quote>
> When the garbage collector calls a destructor for an object of a class that
> has members that are references to garbage collected objects, those
> references are no longer valid. This means that destructors cannot reference
> sub objects. This rule does not apply to auto objects or objects deleted
> with the DeleteExpression.
> The garbage collector is not guaranteed to run the destructor for all
> unreferenced objects. Furthermore, the order in which the garbage collector
> calls destructors for unreference objects is not specified.
> <\quote>

That does preclude the use of any kind of resource-management object being used in composition, does it not? In which case, D's OO is seriously hamstrung.

Now if D would allow embedding of auto members (of auto or non-auto classes), then we'd have an answer. (Sounds
suspiciously like C++, of course, but then this is something C++ got very right.)

> It would be nice if we lived in a world where the GC could be fast and run destructors "nicely" but given the choice I would go for GC performance. Destructors should be a very weak construct. You never know when or if they will run so most of the time relying on them is a bug in disguise. Google around for web pages about Finalizers and Java and you'll get an idea how everyone in the Java world says not to use them. Remember all this destructor running happens on every GC pass, not just program exit.

I agree with all that you say, but just want to mention that I think your emphasis is a little off. They're a deprecated technique for correctness rather than efficiency, surely?



August 26, 2004
Arcane Jill wrote:

> In article <cgj8qb$2ler$1@digitaldaemon.com>, pragma says...
> 
>>>The garbage collector is not guaranteed to run the destructor for all unreferenced objects.
> 
> Please see THIS POST from Walter, and the discussion before and after it: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/3488
> 
> In particular, Walter said: "I must have misspoke, because when the gc collects an object, it *does* run the destructor." (Walter's emphasis on *does*).
> 
> I have security apps planned which rely on Walter's statement being true. Where is this "not guaranteed" quote in the manual? I couldn't find it. Basically - help! Who's right? Walter, or the manual? Walter, please could you clarify (again), and fix the manual if it's wrong.
> 
> Jill

The manual and Walter's post are consistent. The GC runs the destructor when it collects an object but it isn't guaranteed to collect all unreferenced objects (due to ambiguous references etc).
August 26, 2004
In article <cgkkeq$925$1@digitaldaemon.com>, Ben Hinkle says...

>The manual and Walter's post are consistent. The GC runs the destructor when it collects an object but it isn't guaranteed to collect all unreferenced objects (due to ambiguous references etc).

Okay, but presumably it *is* guaranteed to collect everything not yet collected (and to call all remaining destructors) at program exit. Right?



August 26, 2004
Arcane Jill wrote:

> In article <cgkkeq$925$1@digitaldaemon.com>, Ben Hinkle says...
> 
>>The manual and Walter's post are consistent. The GC runs the destructor when it collects an object but it isn't guaranteed to collect all unreferenced objects (due to ambiguous references etc).
> 
> Okay, but presumably it *is* guaranteed to collect everything not yet collected (and to call all remaining destructors) at program exit. Right?

nope - at program exit it scans static data for roots so any object reference stored in a static variable will never get collected. I don't know if removing static data from the final scan would cause problems.