[Python-Dev] finalization again

Barry A. Warsaw bwarsaw@cnri.reston.va.us
Tue, 7 Mar 2000 14:24:39 -0500 (EST)


>>>>> "TP" =3D=3D Tim Peters <tim_one@email.msn.com> writes:

    TP> 1. I don't know why JPython doesn't execute __del__ methods at
    TP> all now, but have to suspect that the Java rules imply an
    TP> implementation so grossly inefficient in the presence of
    TP> __del__ that Barry simply doesn't want to endure the speed
    TP> complaints.

Actually, it was JimH that discovered this performance gotcha.  The
problem is that if you want to support __del__, you've got to take the
finalize() hit for every instance (i.e. PyInstance object) and it's
just not worth it.

<doing!> I just realized that it would be relatively trivial to add a
subclass of PyInstance differing only in that it has a finalize()
method which would invoke __del__().  Now when the class gets defined,
the __del__() would be mined and cached and we'd look at that cache
when creating an instance.  If there's a function there, we create a
PyFinalizableInstance, otherwise we create a PyInstance.  The cache
means you couldn't dynamically add a __del__ later, but I don't think
that's a big deal.  It wouldn't be hard to look up the __del__ every
time, but that'd be a hit for every instance creation (as opposed to
class creation), so again, it's probably not worth it.

I just did a quick and dirty hack and it seems at first blush to
work.  I'm sure there's something I'm missing :).

For those of you who don't care about JPython, you can skip the rest.

Okay, first the Python script to exercise this, then the
PyFinalizableInstance.java file, and then the diffs to PyClass.java.

JPython-devers, is it worth adding this?

-------------------- snip snip --------------------del.py
class B:
    def __del__(self):
        print 'In my __del__'

b =3D B()
del b

from java.lang import System
System.gc()
-------------------- snip snip --------------------PyFinalizableInstanc=
e.java
// Copyright =A9 Corporation for National Research Initiatives

// These are just like normal instances, except that their classes incl=
uded
// a definition for __del__(), i.e. Python's finalizer.  These two inst=
ance
// types have to be separated due to Java performance issues.

package org.python.core;

public class PyFinalizableInstance extends PyInstance=20
{
    public PyFinalizableInstance(PyClass iclass) {
        super(iclass);
    }

    // __del__ method is invoked upon object finalization.
    protected void finalize() {
        __class__.__del__.__call__(this);
    }
}
-------------------- snip snip --------------------
Index: PyClass.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /projects/cvsroot/jpython/dist/org/python/core/PyClass.java,v=

retrieving revision 2.8
diff -c -r2.8 PyClass.java
*** PyClass.java=091999/10/04 20:44:28=092.8
--- PyClass.java=092000/03/07 19:02:29
***************
*** 21,27 ****
         =20
      // Store these methods for performance optimization
      // These are only used by PyInstance
!     PyObject __getattr__, __setattr__, __delattr__, __tojava__;
 =20
      // Holds the classes for which this is a proxy
      // Only used when subclassing from a Java class
--- 21,27 ----
         =20
      // Store these methods for performance optimization
      // These are only used by PyInstance
!     PyObject __getattr__, __setattr__, __delattr__, __tojava__, __del=
__;
 =20
      // Holds the classes for which this is a proxy
      // Only used when subclassing from a Java class
***************
*** 111,116 ****
--- 111,117 ----
          __setattr__ =3D lookup("__setattr__", false);
          __delattr__ =3D lookup("__delattr__", false);
          __tojava__ =3D lookup("__tojava__", false);
+         __del__ =3D lookup("__del__", false);
      }
         =20
      protected void findModule(PyObject dict) {
***************
*** 182,188 ****
      }
 =20
      public PyObject __call__(PyObject[] args, String[] keywords) {
!         PyInstance inst =3D new PyInstance(this);
          inst.__init__(args, keywords);
          return inst;
      }
--- 183,194 ----
      }
 =20
      public PyObject __call__(PyObject[] args, String[] keywords) {
!         PyInstance inst;
!         if (__del__ =3D=3D null)
!             inst =3D new PyInstance(this);
!         else
!             // the class defined an __del__ method
!             inst =3D new PyFinalizableInstance(this);
          inst.__init__(args, keywords);
          return inst;
      }