On Mar 21, 10:28 am, Aaron Brady <castiro...@gmail.com> wrote: > On Mar 21, 9:50 am, "andrew cooke" <and...@acooke.org> wrote: > > > > > Aaron Brady wrote: > > > On Mar 21, 7:54 am, "andrew cooke" <and...@acooke.org> wrote: > > >> they should not be used to do things like flushing and closing > > >> files, for example. > > > What is your basis for this claim, if it's not the mere unreliability > > > of finalization? IOW, are you not merely begging the question? > > > I'm not sure it's clear, but I was talking about Java. > > > As Paul implied, a consequence of completely automated garbage management > > is that it is (from a programmer's POV) deterministic. So it's a > [indeterministic] > > programming error to rely on the finalizer to free resources that don't > > follow that model (ie any resource that's anything other that > [than] > > reasonable > > amounts of memory). > > > That's pretty much an unavoidable consequence of fully automated garbage > > collection. You can pretend it's not, and try using finalizers for other > > work if you want. That's fine - it's your code, not mine. I'm just > > explaining how life is. > > > Andrew > > My point is, that garbage collection is able to detect when there are > no program-reachable references to an object. Why not notify the > programmer (the programmer's objects) when that happens? If the > object does still have other unreachable references, s/he should be > informed of that too. snip
I took the liberty of composing a sample cyclic reference detector. I will post the class definition later on in the discussion (when and if). The 'run' method resets the globals to a sample graph, as illustrated. 'p' and 's' start out with one simulated program-visible reference each. As you see, the details are already long and boring (yum). I added comments post-facto. >>> run() #only decref 'p' p: (q), q: (pr), r: (q), s: (p) >>> >>> p.decref() #not safe to delete {<p,2>: 1, <q,2>: 0, <r,1>: 0} >>> >>> >>> run() #decref 'p' then 's' p: (q), q: (pr), r: (q), s: (p) >>> >>> p.decref() {<p,2>: 1, <q,2>: 0, <r,1>: 0} >>> >>> s.decref() {<s,0>: 0, <p,2>: 0, <r,1>: 0, <q,2>: 0} <s,0> ALL zero #'s' safe to delete {<p,1>: 0, <q,2>: 0, <r,1>: 0} <p,1> ALL zero #also deletes 'p', also safe finalizing <s,0> >>> >>> >>> run() p: (q), q: (pr), r: (q), s: (p) >>> >>> s.decref() {<s,0>: 0, <p,3>: 1, <r,1>: 0, <q,2>: 0} {<p,2>: 1, <q,2>: 0, <r,1>: 0} finalizing <s,0> #deletion >>> >>> p.decref() {<p,1>: 0, <q,2>: 0, <r,1>: 0} <p,1> ALL zero #'p' safe to delete >>> >>> >>> run() p: (q), q: (pr), r: (q), s: (p) >>> >>> s.decref() {<s,0>: 0, <p,3>: 1, <q,2>: 0, <r,1>: 0} {<p,2>: 1, <q,2>: 0, <r,1>: 0} finalizing <s,0> #'p' not safe, reference still visible We notice the duplicate 'all zero' indicator on run #2. The cycle detector ran on 's.decref', then 's' called 'p.decref', then the cycle detector ran on that. 'q' and 'r' are safe to delete on runs 2 and 3. Here is the implementation of 'final': def final( self ): for _, v in self.__dict__.items( ): if not isinstance( v, G ): continue v.decref( ) print( 'finalizing', self ) The object should be asked to finish its references (cyclic only?), but remain alive. The programmer should see that the state is consistent. Later, its __del__ will be called. We can decide that '__leave_reachability__' will be called without nesting; and/or that '__del__' will be called without nesting, by breaking finalization in to two steps. FTR, this makes __leave_reachability__ about the equivalent of tp_clear, since tp_traverse is prior defined for user-defined types. -- http://mail.python.org/mailman/listinfo/python-list