Both the __init__ and __del__ issues are now fixed and pushed to CodePlex.

> -----Original Message-----
> From: users-boun...@lists.ironpython.com [mailto:users-
> boun...@lists.ironpython.com] On Behalf Of William Reade
> Sent: Tuesday, July 21, 2009 5:31 AM
> To: Discussion of IronPython
> Subject: Re: [IronPython] object lifecycle issues
>
> Hi Dino
>
> I don't *think* that's the case -- the stub has a __del__ method, that
> should never get called, purely to work around that bug (or possibly a
> subtly different one: I internally characterised it as "an object won't
> get __del__ed unless the type it was created as had a __del__ method,
> at the time it was created", which doesn't *quite* match your example).
> I guess it's one of the ones that never made it onto Codeplex... it's
> there now, at
> http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=23564
>
> The repro for for issue #2 -- which requires current ironclad with
> appropriate logging -- is attached as x.py. The output, which you can
> see a bit further down, shows what happens when you construct-then-
> delete instances of various numpy data types. In short, the int8 and
> float32 dtypes don't include a CLR type among their immediate bases,
> and do get deleted correctly, while the int32 and
> float64 dtypes do and don't respectively.
>
> Anyway, I'll look into your earlier suggestions -- thank you very much!
>
> x.py output (after a lot of noise from the numpy import)
> ------------------------------------------------------------
> ========================================
>
> start <class 'numpy.int8'>
>
> real new1 <class 'numpy.int8'>
> fake new1 _ironclad_class_stub (<class 'numpy.signedinteger'>,) fake
> new2 (object) 2107 fake init <class 'unknown._ironclad_class_stub'>
> 2107 real new2 <class 'numpy.int8'> 2107
>
> constructed; id is 2107
>
> real del 2107
>
> finished <class 'numpy.int8'>
>
> ========================================
>
> start <class 'numpy.int32'>
>
> real new1 <class 'numpy.int32'>
> fake new1 _ironclad_class_stub (<class 'numpy.signedinteger'>, <type
> 'int'>) fake new2 (int) 2111 fake init <class
> 'unknown._ironclad_class_stub'> 2111 real new2 <class 'numpy.int32'>
> 2111
>
> constructed; id is 2111
>
>
> finished <class 'numpy.int32'>
>
> ========================================
>
> start <class 'numpy.float32'>
>
> real new1 <class 'numpy.float32'>
> fake new1 _ironclad_class_stub (<class 'numpy.floating'>,) fake new2
> (object) 2116 fake init <class 'unknown._ironclad_class_stub'> 2116
> real new2 <class 'numpy.float32'> 2116
>
> constructed; id is 2116
>
> real del 2116
>
> finished <class 'numpy.float32'>
>
> ========================================
>
> start <class 'numpy.float64'>
>
> real new1 <class 'numpy.float64'>
> fake new1 _ironclad_class_stub (<class 'numpy.floating'>, <type
> 'float'>) fake new2 (float) 2121 fake init <class
> 'unknown._ironclad_class_stub'> 2121 real new2 <class 'numpy.float64'>
> 2121
>
> constructed; id is 2121
>
>
> finished <class 'numpy.float64'>
> ------------------------------------------------------------
>
> ...and the internal logging is as follows:
>
> ------------------------------------------------------------
>         public const string CLASS_STUB_CODE = @"
> def __new__(cls, *args, **kwargs):
>     print 'fake new1', cls.__name__, cls.__bases__
>     if issubclass(cls, int):
>         result = int.__new__(cls, args[0])
>         print 'fake new2 (int)', id(result)
>         return result
>     if issubclass(cls, float):
>         result = float.__new__(cls, args[0])
>         print 'fake new2 (float)', id(result)
>         return result
>     result = object.__new__(cls)
>     print 'fake new2 (object)', id(result)
>     return result
>
> def __init__(self, *args, **kwargs):
>     print 'fake init', type(self), id(self)
>
> def __del__(self):
>     print 'fake del', id(self)
>
> def __setattr__(self, name, value):
>     object.__setattr__(self, name, value)
>
> _ironclad_class_stub = _ironclad_metaclass('_ironclad_class_stub',
> _ironclad_bases, {
>     '__new__': __new__,
>     '__init__': __init__,
>     '__del__': __del__,
>     '__setattr__': __setattr__,
> })
> ";
>
>         public const string CLASS_CODE = @"
> def __new__(cls, *args, **kwargs):
>     print 'real new1', cls
>     result = cls._dispatcher.newfunc('{0}.tp_new', cls, args, kwargs)
>     print 'real new2', cls, id(result)
>     return result
>
> def __del__(self):
>     print 'real del', id(self)
>     self._dispatcher.ic_destroy(self)
>
> _ironclad_class_attrs['__new__'] = __new__
> _ironclad_class_attrs['__del__'] = __del__
>
> _ironclad_class = _ironclad_metaclass('{0}', _ironclad_bases,
> _ironclad_class_attrs)
> _ironclad_class.__doc__ = '''{2}'''
> _ironclad_class.__module__ = '{1}'
> ";
> ------------------------------------------------------------
>
> ...while the code that actually constructs ipy objects around cpy
> objects looks like this:
>
> ------------------------------------------------------------
>
>         private void
>         ActualiseArbitraryObject(IntPtr ptr)
>         {
>             IntPtr typePtr = CPyMarshal.ReadPtrField(ptr,
> typeof(PyObject), "ob_type");
>             PythonType type_ = (PythonType)this.Retrieve(typePtr);
>
>             object[] args = new object[]{};
>             if (Builtin.issubclass(type_, TypeCache.Int32))
>             {
>                 args = new object[] { CPyMarshal.ReadIntField(ptr,
> typeof(PyIntObject), "ob_ival") };
>             }
>             if (Builtin.issubclass(type_, TypeCache.Double))
>             {
>                 args = new object[] { CPyMarshal.ReadDoubleField(ptr,
> typeof(PyFloatObject), "ob_fval") };
>             }
>             // ...
>
>             object obj = PythonCalls.Call(this.classStubs[typePtr],
> args);
>             Builtin.setattr(this.scratchContext, obj, "__class__",
> type_);
>             // ...
>         }
> ------------------------------------------------------------
>
> BTW: As it happens, the stub class is now a sibling of the real class
> rather than a subclass, because it feels cleaner. Regardless, the
> behaviour is identical in each case.
>
> Cheers
> william
>
> Dino Viehland wrote:
> > Could this be issue 2?
> >
> > class Real(object):
> >     def __new__(cls, *args, **kwargs):
> >         print 'real new'
> >         return object.__new__(Stub)
> >     #def __del__(self): pass     # uncomment me and this works as
> expected
> >
> > class Stub(Real):
> >     def __del__(self):
> >         print "I've been finalized"
> >
> > f = Real(1.0)
> > del f
> >
> > import sys
> > if sys.platform == 'clr':
> >     import clr
> >     from System import GC
> >     for _ in range(4):
> >         GC.Collect()
> >         GC.WaitForPendingFinalizers()
> >
> >
> >
> >> -----Original Message-----
> >> From: users-boun...@lists.ironpython.com [mailto:users-
> >> boun...@lists.ironpython.com] On Behalf Of William Reade
> >> Sent: Monday, July 20, 2009 9:38 AM
> >> To: Discussion of IronPython
> >> Subject: [IronPython] object lifecycle issues
> >>
> >> Hi all
> >>
> >> I have two problems that are at least somewhat related:
> >>
> >> +++ Issue 1 (probably your bug):
> >>
> >> ---------------------------------------------------------------
> >> C:\dev\ironclad - Copy>ipy y.py
> >> real new
> >> stub new
> >> real init
> >> real del
> >>
> >> C:\dev\ironclad - Copy>python y.py
> >> real new
> >> stub new
> >> stub init
> >> real del
> >> ---------------------------------------------------------------
> >>
> >> I freely admit that the attached code is pretty weird, but I really
> >> do need to do stuff like this in Ironclad. The difference in
> >> behaviour may or may not be responsible for certain failing
> >> numpy/scipy tests -- I'm not sure how to tell -- but I'd enormously
> appreciate a fix.
> >>
> >> I'd report the issue on Codeplex, but trying to visit the issue
> >> tracker just leaves my browser spinning forever. Speaking of which:
> >> is there any alternative way of reporting bugs that doesn't make me
> >> feel as if I'm spamming the list with out-of-band noise? I'm pretty
> >> sure that a few bugs have just dropped off my stack in the last few
> >> months, just because I got tired of waiting for Codeplex to start
> working.
> >>
> >> +++ Issue 2 (almost certainly my bug):
> >>
> >> In a nearly identical* situation -- close enough that I can't say
> how
> >> it's actually different -- f will never get its __del__ method
> called
> >> (the object is destroyed -- a WeakReference to it knows it's dead --
> >> but the __del__ call never happens).
> >>
> >> For context: I have *very* similar classes, whose instances are
> >> constructed in exactly the weird way demonstrated in the attached
> >> file, and which work fine. The only difference between the cases
> that
> >> work and the cases that don't is that the broken cases multiply
> >> inherit from ipy types which wrap CLR types (int and float (and
> maybe
> >> str, although I haven't tested that one)), while the working cases
> >> have simple chains of single inheritance from user-defined types all
> the way up to object.
> >> However, the attached repro doesn't show my problem, so it's clearly
> >> not
> >> *just* to do with multiply inheriting from CLR types.
> >>
> >> Does anyone have any idea what I might be doing wrong? I know this
> is
> >> a vague request, but I'm running out of ideas, and I'd really
> >> appreciate some input from someone who understands precisely what
> all
> >> those ipy MetaFoo classes are doing.
> >>
> >> Cheers
> >> william
> >>
> >>
> >> * the attached file started life as an attempt to repro the __del__
> >> issue, and I incidentally noticed the __init__ issue.
> >>
> > _______________________________________________
> > Users mailing list
> > Users@lists.ironpython.com
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >
> >

_______________________________________________
Users mailing list
Users@lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com

Reply via email to