[Python-Dev] Changing existing class instances

A.M. Kuchling akuchlin@mems-exchange.org
Wed, 19 Jan 2000 23:19:33 -0500


Currently, when you replace a class definition with an updated
version, it's really difficult to change existing class instances;
you'd have to essentially sweep every Python object and check if it's
an instance, starting at roots such as __main__ and sys.modules.  This
makes developing code in a long-running process difficult, Zope being
the best example of this.  When you modify a class definition used by
Zope code, you can't update existing instances floating around in
memory.

Over dinner, a friend and I were discussing this, and we thought it
probably isn't difficult to add an extra level of indirection to allow
fixing this.  The only other option we could think of is either the
complete scan of all objects, or inserting a forwarding pointer into
PyClassObjects that points to the replacing class if !NULL, and then
chase pointers when accessing PyInstanceObject->in_class.

A quick hack to implement the extra indirection took about
half an hour.  It does these things:

      * Defines a PyClassHandle type:
struct _PyClassHandle {
  PyClassHandle *next;		/* ptr to next PyClassHandle in linked list */
  PyClassObject *klass;		/* The class object */
} ;

      * The in_class attribute of PyInstanceObject becomes a
        PyClassHandle* instead of a PyClassObject*, and all code 
	such as inst->in_class becomes inst->in_class->klass.

      * As a quick hack to allow changing the class object referenced
        by a handle, I added a .forward( <newclassobject> ) method to
        class objects.  This basically does self.handle->klass =
        <newclassobject>.

The end result is that obj.__class__.forward(newclass) changes obj to
be an instance of newclass, and all other instances of obj.__class__
also mutate to become newclass instances.   

Making this purely automatic seems hard; you'd have to catch things
like 'import ftplib; ftplib.FTP = myclass', which would require
automatically calling ftplib.FTP.forward( myclass ) to make all
existing FTP instances mutate.  Would it be worthwhile to export some
hook for doing this in 1.6?  The cost is adding an extra pointer deref
to all access to PyInstanceObject->in_class.

(This could probably also be added to ExtensionClass, and probably
doesn't need to be added to core Python to help out Zope.  Just a
thought...)

-- 
A.M. Kuchling			http://starship.python.net/crew/amk/
Here the skull of a consumptive child becomes part of a great machine for
calculating the motions of the stars. Here, a yellow bird frets within the
ribcage of an unjust man.
    -- Welcome to Orqwith, in DOOM PATROL #22