Title: PyInstance/PyFinalizable do not work with acquired __del__
Type: Severity: normal
Components: Core Versions:
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: amak, fwierzbicki, leouserz, pjenvey
Priority: normal Keywords: patch

Created on 2007-01-12.16:08:30 by leouserz, last changed 2012-08-10.17:57:37 by fwierzbicki.

File name Uploaded Description Edit Remove leouserz, 2007-01-12.16:08:30
PyClassDiff.txt leouserz, 2007-01-12.17:05:00
msg2589 (view) Author: Deleted User leouserz (leouserz) Date: 2007-01-12.16:08:30
__del__ does not appear to work correctly if acquired in jython.  This py script works fine on Python 2.5:

class z:

a = z()
def __del__(a):
    print "DEL"
z.__del__ = __del__
a = None

x = z()
x = None

print dir(z)

class z:
    def __del__(a):
        print "DEL2"
f = z()
f = None

import sys
if(len(sys.argv) > 1):
    import java

z always has its __del__ called even if acquired.  In jython this appears not to work for classes that acquire __del__.  Im not sure of the cause, but I would expect the instance created after acquiring __del__ to fire "DEL" off.  I believe the problem for the second case is because PyClass does not mutate when __del__ is added to it.  Well it mutates but it doesn't appear to reset an internal variable that determines if the new PyInstance will be finalizable or not.  Additionally it appears that PyType defines a variable that is not used: "needs_finalizable".  PyClass looks for __del__ being set not "needs_finalizable".

Now for existing classes this poses a problem.  If __del__ is defined at instantiation time it is a PyFinalizableInstance that is created.  The documentation states that PyFinalizableInstance exists because of performance problems.  It would be good to see what these are.  The only solution I can think of at this moment is to remove PyFinalizableInstance and just make PyInstance with a finalize method.  It could then check on finalize if __del__ exists and do its work.

msg2590 (view) Author: Deleted User leouserz (leouserz) Date: 2007-01-12.17:05:00
A possible fix for the __del__ added after the class is defined is the patch attached.  If an instance is created after this it will be able to create a PyFinalizableInstance.  Now this patch in itself seem problematic.  PyFinalizableInstance doesn't check if its __del__ method has been nulled out.  But this doesn't appear to cause any terrible problems at finalize time.  It still would be better to check things out and not throw a NullPointerException(this appears hidden).

The simplest fix would be to define finalize in PyInstance and check if __del__ is not null in its instclass variable.  If so, execute __del__.  This would probably take care of any problems with mutations on __del__ for all existing instances.  Though I am worried about PyInstances sitting in memory longer than they need to.

File Added: PyClassDiff.txt
msg2591 (view) Author: Deleted User leouserz (leouserz) Date: 2007-01-12.18:07:31
There may be more mutation problems beyond __del__:
    // Store these methods for performance optimization

    // These are only used by PyInstance

    PyObject __getattr__, __setattr__, __delattr__, __tojava__, __del__,


from "PyClass".  If these are mutated I don't see any corresponding change code in the PyClass instance that will reset these fields.


A possible different solution to the mutating __del__ problem is to use a variation on the FinalizerGuardian from Effective Java.
1. Keep track of all PyInstances created by the PyClass
2. If __del__ is altered iterate the PyInstances and add/delete a FinalizerGuardian whose responsibility is to __del__ the PyInstance when itself is finalised.

This is good in that it makes the PyInstance finalizability changable on the fly.  Its bad because its going to add alot of references to the system and a special object for finalising.

msg2592 (view) Author: Deleted User leouserz (leouserz) Date: 2007-01-15.23:11:16
Im not sure if I consider this a definative patch for this problem.  This one is a half-measure.  Its better than before but if there is going to be a real fix, it needs to be more radical.
msg5245 (view) Author: Philip Jenvey (pjenvey) Date: 2009-10-20.05:10:13
When I converted PyClass to exposed annotations I fixed the problem 
solved by this match, of it not resetting its cached version of values 
like __del__ and __getattr__

I've noticed that PyPy seems to emit a RuntimeWarning to the user if 
they apply a __del__ to a type after the fact. Since I don't see this 
happening very often, that sounds like an ok solution for objects that 
didn't have a __del__ in the first place

Though I haven't seen the FinalizerGuardian technique Leo's refering to, 
it's probably worth looking into
msg5733 (view) Author: Philip Jenvey (pjenvey) Date: 2010-04-18.03:34:23
Maybe we don't even need to emit a warning, since we can support adding a __del__ to a type, it's just that the destructor will only work for objects created after the destructor was attached. We just can't support pre-existing instances of that type all of aquiring a __del__

Maybe just documenting this fact somewhere would be enough
msg6868 (view) Author: Alan Kennedy (amak) Date: 2012-03-19.20:42:52
This issue has been open for 5 years now. Does it need to remain open? Is there a simple resolution?
msg7364 (view) Author: Frank Wierzbicki (fwierzbicki) Date: 2012-08-10.17:57:37
This looks closable to me since we have mostly fixed it. Philip, if you think I'm wrong feel free to re-open. I want to get the number of outstanding bugs with "patch" selected down.
Date User Action Args
2012-08-10 17:57:37fwierzbickisetstatus: open -> closed
resolution: out of date
messages: + msg7364
2012-03-20 17:15:30fwierzbickisetnosy: + fwierzbicki
2012-03-19 20:42:52amaksetnosy: + amak
messages: + msg6868
2010-04-18 03:34:24pjenveysetmessages: + msg5733
2009-10-20 05:10:15pjenveysetpriority: low -> normal
nosy: + pjenvey
messages: + msg5245
2009-03-14 02:53:17fwierzbickisetpriority: normal -> low
2008-12-14 18:32:52fwierzbickisetcomponents: + Core, - None
2007-01-12 16:08:30leouserzcreate