RFC: Proposal: Deterministic Object Destruction
On 2/28/18 11:00 PM, ROGER GRAYDON CHRISTMAN wrote:
> On Wed, Feb 28, 2018, Rick Johnson wrote: >
> On Wednesday, February 28, 2018 at 5:02:17 PM UTC-6, Chris Angelico wrote:
>>> Here's one example: reference cycles. When do they get detected?
>>> Taking a really simple situation:
>>> class Foo:
>>> def __init__(self):
>>> self.self = self
>> Can you provide a real world example in which you need an
>> object which circularly references_itself_? This looks like
>> a highly contrived example used to (1) merely win the
>> argument, and (2) Bump fib() up one position from it's
>> current position as "the worst introductory example of how
>> to write a function in the history of programming tutorials"
> If you want something that looks like a real world example,
> consider the very common doubly-linked list:
> [ 1 ] <---> [ 2 ] <---> [ 3 ] <--.....--> [ N ]
> This is chock-full of reference cycles, everywhere you see a <-->
> Then you have a wrapper List object that has a head referencing
> the 1 node and a tail referencing the N node.
> And you decide you don't need that List any more.
> You could:
> 1) Take the time the code to carefully delete every single node
> in this linked list, taking the time to set all of the internal references to
> None, or
> 2) Just discard your List object, and let the GC take care of the rest.
> Note that removing the list alone does not clear any of the
> reference counts in the picture above, because those internal
> <--> references are all still there. You either have to manually
> remove all the references, or rely on the garbage collector.
> Oh, and for those who claim that reference counting is 'efficient',
> do bear in mind that every single assignment statement increases
> the reference count of one value and possibly reduces the reference
> count of another. So down in the machine or byte-code world,
> every assignment operation is really two arithmetic computations
> and three assignments, which takes 5 times as many operations
> as not doing any reference counting at all.
> So if you have a program that can get by leaving unused memory
> allocated, and can still terminate the program before all the memory
> is claimed, your reference count system is far less efficient than
> relying on a garbage collector that happens to not get activated
> before your program ends.
> Roger Christman
> Pennsylvania State University
Now, of course in a language that WANT'S to make reference counting
work, and allow for deterministic destruction of object happen, all you
need to do is? make one direction of the pointer into a 'weak
reference', and the list control object have a strong pointer to the end
that starts the strong chain and a weak reference to the other, and when
the list control object goes away, so does all the list elements.
Yes, there is a slight speed cost in keeping the reference counts, but
there is also a significant cost to the processing that is needed to run
the garbage collection. And that doesn't include the cost of having to
explicitly manage all resources that aren't memory as you have broken
the RAII concept.
I will agree that many programs many programs don't need precise
destruction for most of their objects, but many can be helped by it for
at least a specific set of them.
I am not sure how hard it would be to implement a really useful
reference counting system in Python, as first you would need a concept
of a weak pointer to deal with cases like your list above (which I don't
think Python has anything like that concept). You would also need to
keep the current garbage collection, to handle the existing cases of
circular references (I disagree with the original complaint that these
are always 'errors', if you know you have garbage collection, the
allowance of cycles knowing they will still get cleaned up is a useful
simplification if you don't need the immediate clean up).