From: gmcm at hypernet.com (Gordon McMillan)
Date: Thu, 20 May 1999 15:00:03 -0500
Subject: Circular references (was: Defining VCL-like framework for Py
In-Reply-To: <199905201737.TAA28177@axil.hvision.nl>
References: <7hvnah$ern$1@cronkite.cc.uga.edu>
Message-ID: <1284891865-6060292@hypernet.com>
Content-Length: 2413
X-UID: 1982                                                 

Ce'Nedra, er, Hans wrote:

> On 20 May 99, Ce'Nedra took her magical amulet and heard Graham
> Matthews say:

> >The problem is that as I understand the Python implementation you can very
> >easily make circular refs the without even knowing you are doing it via
> >globals. Or has this been changed?
> 
> I don't know very much about this subject... I know it can be a
> problem with deleting objects... they sit in memory because there's
> still a reference to them, while you thought you deleted it. I can't
> really give an example though. I didn't hear about circular
> references via globals without even knowing it.
> 
> I'm sure there are people who have more to say on this... *hint*

Oh all right.

I'm not sure where "globals" crept into this. If you have a global 
reference, the referenced object ain't going away. You can have 
*hidden* global references, but that's another problem, and it's not 
particular to Python's ref counting scheme.

The problem is _usually_ a parent / child thing, where each has a 
reference to the other. You cut them loose, but they don't go away 
because each has another object (the other) referencing them.

You don't need to break _both_ references, just one of them. Simple 
way out: give one of the objects a free() method which just says 
"self.parent = None". Now you need to remember to call free() when 
you're done with it.

Another way is to put one of them (the parent, normally) in some
kind of collection, (say, a dict keyed by a name, like id(parent)). 
Tell the child the parent's name and the collection. When you cut the 
parent loose from the dict, it goes away (the child does not directly 
reference it). Then the child goes away (nobody is referencing it).

You can probably think of other ways of dealing with it. The 
important part is recognizing them.  Some of them can be subtle.

 class LivesForever:
   def __init__(self):
     self.me = self

Despite these drawbacks, I generally prefer ref counting to garbage
collection. GC is generally nondeterminant - you know it _will_
happen, but you have no idea _when_. So if your objects have some
kind of outside resource open, you need to have a special free()
method anyway instead of relying on freeing it in the destructor. 

I realize many people feel strongly the other way, and I'm not going 
to fight about it. Neither solution is perfect. I'm just stating my 
preference.

- Gordon




