Surprising behaviour wrt. generated tp_clear and tp_dealloc functions
Hi Cython-Developers, I am using Cython to generate a trivial wrapper for a small subset of the (already small) interface of libp11 (see https://github.com/OpenSC/libp11 for information about libp11). I know a bit about Python extension modules and just wanted to avoid writing all that boiler plate code and decided to given Cython a try. The wrapper was done in a day and no big deal, but lately I got random segmentation faults using it. After a day of debugging I found the cause in my use of the __dealloc__ special method. You may now call me stupid, because it is all in the docs: /You need to be careful what you do in a //__dealloc__()//method. By the time your //__dealloc__()//method is called, the object may already have been partially destroyed and may not be in a valid state as far as Python is concerned, so you should avoid invoking any Python operations which might touch the object. In particular, don't call any other methods of the object or do anything which might cause the object to be resurrected. It's best if you stick to just deallocating C data.// / http://docs.cython.org/src/userguide/special_methods.html?highlight=__deallo... But this did not give me the crucial hint: Currently, any references to Python objects *may* be invalid at the time dealloc is called. This is because Cython generates a tp_clear function for each extension type that calls Py_CLEAR for each object reference. What I would really like to have is a possibility to exempt object attributes from being cleared in tp_clear, by adding a modifier to the cdef: *Exempt all attributes:* cdef noclear class Slots: cdef Context context *Exempt a single attribute:* cdef class Slots: cdef noclear Context context This is probably enough of explanation for the Cython experts, but I would still like to explain what happened in my case and a work around for illustration purposes and in the hope, that this will help somebody else at some time. Background When using the libp11 API, the client must create a Context object which is used for most operations. To query the list of slots where a card (token) could be inserted, there is a PKCS11_enumerate_slots function which returns a newly allocated buffer which contains all slots. Unfortunately this means that the resulting Slot objects can not be deallocated individually, only the whole buffer can be released using PKCS11_release_all_slots. This is completely unpythonic which is why I created a special Slots extension type that manages the storage of the Slot instances. When all Slot instances drop their reference to the Slots instance, the refcount of the Slots instance drops to zero and Python will release it automatically. The Slots type then calls the PKCS11_release_all_slots function to release the storage. This is modelled inside the __dealloc__ method for Slots. Unfortunately, a pointer to the context is required for that call. Therefore Slots also keeps a reference to Context object to keep it alive long enough and to identify the underlying C object. But: At the time when __dealloc__ is called, the tp_clear function already has cleared the context reference. Interestingly, it does not use Py_CLEAR as mandated in the Python documentation (see http://docs.python.org/2/c-api/typeobj.html?highlight=py_clear#PyTypeObject.... and http://docs.python.org/3.3/c-api/typeobj.html?highlight=py_clear#PyTypeObjec...) but instead redirects all Python objects to Py_NONE, which partially hides the problem. Somehow, this is not deterministic and tp_clear may have been called or not before tp_dealloc, therefore the random crashes. Even more funny: tp_clear seems to get only called if the Slots instance is involved in a reference cycle. Example Code I attached an example Cython project. If you build and install it with Cython 0.19, the following Python code will work: from fakep11 import * def works(): ctx = Context() my_slots = ctx.slots() while my_slots: assert ctx.usage_counter == 1 my_slots.pop() assert ctx.usage_counter == 0 But the following code will crash when the garbage collector runs: def crashes(): ctx = Context() slots = ctx.slots() a = {"slot": slots[0]} b = {"slot": slots[1], "cycle": a} a["cycle"] = b This is because a and b refer to each other, creating a cycle, and both refer to a slot, pulling the Slots instance into the object graph of the cycle. For this reason, tp_clear will be called for slots before tp_dealloc is called, leaving tp_dealloc with invalid data. Conclusion 1. As somebody who wrote Python extension modules manually before, I fell into this trap because I never implemented tp_clear. Reference cycles were a non-issue to me, since the wrapped objects could not refer to Python objects. Interestingly, SWIG does not seem to have any support for calling tp_clear it seems. 2. IMHO tp_clear should really use Py_CLEAR which would at least make this case a solid segfault. 3. Generating tp_clear functions is a feature that can do some harm, there I propose to allow to disable it. Work around For my current project I worked around this problem by managing the Python references manually by declaring them as PyObject* as in this diff: diff -r f2afc4865bbc fakep11.pyx --- a/fakep11.pyx Sat Apr 20 23:43:00 2013 +0200 +++ b/fakep11.pyx Sun Apr 21 23:50:10 2013 +0200 @@ -1,5 +1,10 @@ cimport cython +cdef extern from "Python.h": + ctypedef struct PyObject + void Py_INCREF(PyObject *) + void Py_DECREF(PyObject *) + cdef extern from "fakep11c.h": ctypedef struct fakep11_context: @@ -35,17 +40,19 @@ @cython.internal cdef class Slots: - cdef Context context + cdef PyObject *context cdef unsigned int nslots cdef fakep11_slot *slots def __cinit__(self, Context context): - self.context = context + self.context = <PyObject*> context + Py_INCREF(self.context) self.slots = fakep11_enumerate(context.imp, &self.nslots) def __dealloc__(self): print "Slots dealloc" - fakep11_release_all(self.context.imp, self.slots, self.nslots) + fakep11_release_all((<Context>self.context).imp, self.slots, self.nslots) + Py_DECREF(self.context) def as_list(self): l = [None] * self.nslots That way I have full control over the reference counting and can make sure that context is a valid reference when __dealloc__ is called. Please find my fake libp11 wrapper example code attached, as well as a small patch for the documentation documenting the current status. Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Hi, Torsten Landschoff, 21.04.2013 23:57:
I am using Cython to generate a trivial wrapper for a small subset of the (already small) interface of libp11 (see https://github.com/OpenSC/libp11 for information about libp11). I know a bit about Python extension modules and just wanted to avoid writing all that boiler plate code and decided to given Cython a try.
The wrapper was done in a day and no big deal, but lately I got random segmentation faults using it.
After a day of debugging I found the cause in my use of the __dealloc__ special method. You may now call me stupid, because it is all in the docs: [...] But this did not give me the crucial hint: Currently, any references to Python objects *may* be invalid at the time dealloc is called. This is because Cython generates a tp_clear function for each extension type that calls Py_CLEAR for each object reference.
Correct, together with your complete analysis (thanks for writing it up). For objects participating in a reference cycle, the cyclic garbage collector will try to break the cycle at an arbitrary object, which may or may not be yours. Thus the unpredictable segfaults. Thanks for bringing this up. Your use case is not uncommon, and it's worth making it easier to handle. I also agree that setting fields to None is probably worse for the innocent user than just setting them to NULL. IIRC, we chose to set everything to None because that's something users can handle in their code. You can test an attribute for None in your __dealloc__ code, but you can't test it for NULL. OTOH, I'm not sure there are many use cases for gracefully handling a cleared reference in __dealloc__(). If there really is something to clean up, then being able to test for None won't usually help much. It will prevent a crash, but also the proper cleanup.
What I would really like to have is a possibility to exempt object attributes from being cleared in tp_clear, by adding a modifier to the cdef:
*Exempt all attributes:*
cdef noclear class Slots:
cdef Context context
That would be a class decorator. Totally makes sense to me. In fact, a decorator to disable GC for a type would also make sense.
*Exempt a single attribute:*
cdef class Slots:
cdef noclear Context context
I would like to avoid adding a separate modifier here. This could also be handled in a class decorator that lists the excluded attributes. My intuition tells me that by far the most common use cases are to exclude either the entire type or exactly one attribute (as in your case, and the lxml package has a similar need). Cython could also adopt a policy of automatically excluding attributes referencing types that are known to be safe, e.g. basic builtin types. No big savings, but it may drop the need for a useless tp_clear() entirely in some cases, and that might have an impact on the GC cleanup time, as the GC might succeed in breaking the cycle more quickly. Reconsidering tp_traverse() would also be worth it in this case. In some cases, we could even drop the type's GC support completely. Think of a type that only has C typed fields, except for one byte string attribute. That would currently trigger the GC support for no good reason. Another possibility (which I think we considered back in the old days) would be to automatically exclude fields from tp_clear() that are being syntactically referenced in a corresponding __dealloc__() method. However, that's obviously error prone and won't catch all cases (e.g. usage in subtypes, calling cleanup functions from __dealloc__, "if DEBUG: print(self.attr)", ...), so I guess we'd rather not go that route. Explicit is definitely better than implicit here. Stefan
But this did not give me the crucial hint: Currently, any references to Python objects *may* be invalid at the time dealloc is called. This is because Cython generates a tp_clear function for each extension type that calls Py_CLEAR for each object reference. Correct, together with your complete analysis (thanks for writing it up). For objects participating in a reference cycle, the cyclic garbage
collector will try to break the cycle at an arbitrary object, which may or may not be yours. Thus the unpredictable segfaults. Perhaps I am misreading the CPython source code but it appears to me
Thanks for bringing this up. Your use case is not uncommon, and it's worth making it easier to handle. I am glad that you see it this way. I also think that this will happen often, but of course I was not sure if you would agree. I also agree that setting fields to None is probably worse for the innocent user than just setting them to NULL. IIRC, we chose to set everything to None because that's something users can handle in their code. You can test an attribute for None in your __dealloc__ code, but you can't test it for NULL. Hmm, okay, that's a good point that I have missed. Wouldn't it be
OTOH, I'm not sure there are many use cases for gracefully handling a cleared reference in __dealloc__(). If there really is something to clean up, then being able to test for None won't usually help much. It will prevent a crash, but also the proper cleanup. Agreed. That would be a class decorator. Totally makes sense to me. In fact, a decorator to disable GC for a type would also make sense. That would be a great feature. After all, traversing the Python objects in my example is of no use as they can not create a cycle.
*Exempt a single attribute:*
cdef class Slots:
cdef noclear Context context I would like to avoid adding a separate modifier here. This could also be handled in a class decorator that lists the excluded attributes. My intuition tells me that by far the most common use cases are to exclude either the entire type or exactly one attribute (as in your case, and the lxml package has a similar need). I believe your intuition matches reality. :-) A class decorator supporting a list of excluded attributes would be fine! Cython could also adopt a policy of automatically excluding attributes referencing types that are known to be safe, e.g. basic builtin types. No big savings, but it may drop the need for a useless tp_clear() entirely in some cases, and that might have an impact on the GC cleanup time, as the GC might succeed in breaking the cycle more quickly. Reconsidering One could even think about building a graph of possible object relationships based on the type declaration for the Python attributes. In the example, Slot refers only to Slots and Slots only to Context, so
Hi Stefan, thank you for your extremely quick reply! On 04/22/2013 07:31 AM, Stefan Behnel wrote: that each and every object in the reference cycle will get its tp_clear called. http://hg.python.org/cpython/file/9c0a677dbbc0/Modules/gcmodule.c#l782 Ah, okay, I get it. The loop will terminate when it reaches an object that actually breaks the cycle in tp_clear: The decref will cascade over all objects in the cycle. possible to allow the special check "foo is NULL" for any Python object? Of course Cython usually shields the developer from the possibility that foo actually becomes NULL so why bother. :-) these can't build a cycle.
Another possibility (which I think we considered back in the old days) would be to automatically exclude fields from tp_clear() that are being syntactically referenced in a corresponding __dealloc__() method. However, that's obviously error prone and won't catch all cases (e.g. usage in subtypes, calling cleanup functions from __dealloc__, "if DEBUG: print(self.attr)", ...), so I guess we'd rather not go that route. Explicit is definitely better than implicit here. But a good idea would be to warn if __dealloc__ actually references a Python attribute that tp_clear could have cleared, with a pointer to the class decorator that exempts the attribute/instance from tp_clear.
Thanks and greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Torsten Landschoff, 22.04.2013 13:07:
On 04/22/2013 07:31 AM, Stefan Behnel wrote:
But this did not give me the crucial hint: Currently, any references to Python objects *may* be invalid at the time dealloc is called. This is because Cython generates a tp_clear function for each extension type that calls Py_CLEAR for each object reference. Correct, together with your complete analysis (thanks for writing it up). For objects participating in a reference cycle, the cyclic garbage
collector will try to break the cycle at an arbitrary object, which may or may not be yours. Thus the unpredictable segfaults.
Perhaps I am misreading the CPython source code but it appears to me that each and every object in the reference cycle will get its tp_clear called.
http://hg.python.org/cpython/file/9c0a677dbbc0/Modules/gcmodule.c#l782
Ah, okay, I get it. The loop will terminate when it reaches an object that actually breaks the cycle in tp_clear: The decref will cascade over all objects in the cycle.
In any case, there are no guarantees about which objects within a reference cycle will be cleared or not.
I also agree that setting fields to None is probably worse for the innocent user than just setting them to NULL. IIRC, we chose to set everything to None because that's something users can handle in their code. You can test an attribute for None in your __dealloc__ code, but you can't test it for NULL.
Hmm, okay, that's a good point that I have missed. Wouldn't it be possible to allow the special check "foo is NULL" for any Python object? Of course Cython usually shields the developer from the possibility that foo actually becomes NULL so why bother. :-)
Exactly - an extremely special case. It's an inherent property of the Cython language that user visible references are never NULL. (minus evil C code, obviously.)
That would be a class decorator. Totally makes sense to me. In fact, a decorator to disable GC for a type would also make sense.
That would be a great feature. After all, traversing the Python objects in my example is of no use as they can not create a cycle.
Cython could also adopt a policy of automatically excluding attributes referencing types that are known to be safe, e.g. basic builtin types. No big savings, but it may drop the need for a useless tp_clear() entirely in some cases, and that might have an impact on the GC cleanup time, as the GC might succeed in breaking the cycle more quickly. Reconsidering
One could even think about building a graph of possible object relationships based on the type declaration for the Python attributes. In the example, Slot refers only to Slots and Slots only to Context, so these can't build a cycle.
Interesting. Yes, that might work. And it's even easy to control when we allow users to override this decision explicitly using a class decorator.
a good idea would be to warn if __dealloc__ actually references a Python attribute that tp_clear could have cleared, with a pointer to the class decorator that exempts the attribute/instance from tp_clear.
That's a good idea. Any help with this is appreciated. :) Stefan
Exactly - an extremely special case. It's an inherent property of the Cython language that user visible references are never NULL. (minus evil C code, obviously.) Suits me.
a good idea would be to warn if __dealloc__ actually references a Python attribute that tp_clear could have cleared, with a pointer to the class decorator that exempts the attribute/instance from tp_clear. That's a good idea.
Any help with this is appreciated. :) How can I help? If you want, I can attempt to create a patch and ask you if I don't make any progress. I do not have a good grip at Cython sourcecode yet, so if you can give me a head start by pointing out the locations where I can inject the new behaviour this would be most welcome. About the object graph analysis I do not know if that is easily added. I
Hi Stefan, On 04/22/2013 01:50 PM, Stefan Behnel wrote: thought it might be because Cython already has some type inference in place!? Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Torsten Landschoff, 22.04.2013 13:56:
On 04/22/2013 01:50 PM, Stefan Behnel wrote:
a good idea would be to warn if __dealloc__ actually references a Python attribute that tp_clear could have cleared, with a pointer to the class decorator that exempts the attribute/instance from tp_clear.
That's a good idea.
Any help with this is appreciated. :)
How can I help? If you want, I can attempt to create a patch and ask you if I don't make any progress.
Please do. Just ask back on this list if there's anything that's not clear to you.
I do not have a good grip at Cython sourcecode yet, so if you can give me a head start by pointing out the locations where I can inject the new behaviour this would be most welcome.
The implementations of tp_clear() etc. are in ModuleNode.py. For example, switching off the clearing of known Python builtin types can be done directly in generate_clear_function() by testing the type of the "entry" (a symbol table entry, specifically a name a type attribute in this case). See the end of Builtin.py (and its usage) for known builtins. You might want to add a list of safe builtin types to Builtin.py and use it in other places. There's precedence in "types_that_construct_their_instance". I'd definitely start by writing a test. Test suite and test runner are explained here: http://wiki.cython.org/HackerGuide#Thetestsuite Regarding the decision about GC participation, there's a method needs_gc() in the CClassScope class in Symtab.py. Making that smarter should be enough to disable GC support in safe cases. You can clone Cython on github and give us changes to review in your own repo there.
About the object graph analysis I do not know if that is easily added. I thought it might be because Cython already has some type inference in place!?
No type inference needed. Object attributes are either explicitly typed as a specific extension (or builtin) type, or they are just plain objects, in which case we must assume that they can introduce refcycles. You can start by walking the attribute type graph in needs_gc(). (I don't think it's called all that often, but in the worst case, the result should be cachable.) Just let a debugger stop inside of it and take a close look at what you see around you. Basically, the "scope" of an extension type knows what is defined inside of that type. That's how you get at the reference graph. For a bonus, walking type graphs might be a generally usable feature, so it may (or may not) be a good idea to implement a general way of doing this, maybe as some kind of generator. Oh, and your code needs to be compatible with Py2.4, as well as 2to3-able to run in Py3.x. But these things are usually quite easily fixable after the fact. Stefan
Hi Stefan, sorry for the delay, I was in the US for parental leave. I had hoped to find some time to work on the promised patch over there, but I fell short. On 04/22/2013 02:28 PM, Stefan Behnel wrote:
Please do. Just ask back on this list if there's anything that's not clear to you. I attached my current (trivial) patch. Currently I only support a decorator
@cython.noclear cdef class ... to inhibit generation of tp_clear. Before I continue with this approach I am wondering about the API. Is noclear usable as a name? I think not because nobody will know what it is talking about. But I do not know how to press the information "do not generate the tp_clear slot which will clear references to break reference cycles during GC" into a short name. Perhaps something along the lines of "@cython.gc_keep_references" or "@cython.exempt_from_gc_cycle_breaker"!? How should the decorator to completely disable GC for a class be called? @cython.nogc? @cython.refcounted (because the class will only support cleanup via reference counting)? Any input appreciated. Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Torsten Landschoff, 11.07.2013 00:10:
I attached my current (trivial) patch. Currently I only support a decorator
@cython.noclear cdef class ...
to inhibit generation of tp_clear.
Thanks, looks ok to me. Please open a pull request on github for it.
Before I continue with this approach I am wondering about the API. Is noclear usable as a name? I think not because nobody will know what it is talking about.
I think that name is as good as any. It could be "no_gc_clear", if you find that clearer. It hints at GC, at least. I think that should be part of the name somehow. Please also document it somewhere in the extension types doc section (in the user guide): https://github.com/cython/cython/blob/master/docs/src/userguide/extension_ty...
But I do not know how to press the information "do not generate the tp_clear slot which will clear references to break reference cycles during GC" into a short name.
It doesn't have to say it all, especially since it's a very special purpose thing. Eventually, Cython should be able to reduce the need even further, so users will only have to apply it when they already know that they need it. The docs should answer the question "is there a way to do this?"
How should the decorator to completely disable GC for a class be called? @cython.nogc?
+1 People who apply it will already have to know the difference between reference counting and cyclic garbage collection, otherwise, they wouldn't even know why to use it.
@cython.refcounted (because the class will only support cleanup via reference counting)?
No, all Python objects are ref-counted. Stefan
Hi Stefan, On 07/14/2013 10:39 AM, Stefan Behnel wrote:
I attached my current (trivial) patch. Currently I only support a decorator
@cython.noclear cdef class ...
to inhibit generation of tp_clear. Thanks, looks ok to me. Please open a pull request on github for it. I'd like to remove some code duplication I introduced in my changes and add the feature to exclude specific attributes from clearing. Before I continue with this approach I am wondering about the API. Is noclear usable as a name? I think not because nobody will know what it is talking about. I think that name is as good as any. It could be "no_gc_clear", if you find
Torsten Landschoff, 11.07.2013 00:10: that clearer. It hints at GC, at least. I think that should be part of the name somehow. Agreed. So there will be the following decorator:
@cython.no_gc_clear class ... to disable generation of the clear method and @cython.no_gc class ... to disable GC entirely. Okay for you? I'd also like to support @cython.no_gc_clear("keepthis", "keepthat") to omit specific attributes from clear handling. I am not sure though how to declare that decorator in directive_types. Would something like this work: directive_types = { 'final' : bool, # final cdef classes and methods # ... 'no_gc_clear': one_of('bool', 'list'), # ... } ?? How would I tell the parser that it should accept the strings as *args of the decorator (if you know what I mean)?
Please also document it somewhere in the extension types doc section (in the user guide):
https://github.com/cython/cython/blob/master/docs/src/userguide/extension_ty... Thanks for the pointer, I was wondering about the right documentation set to change.
Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Hi again, On 07/14/2013 10:39 AM, Stefan Behnel wrote:
Torsten Landschoff, 11.07.2013 00:10:
I attached my current (trivial) patch. Currently I only support a decorator
@cython.noclear cdef class ...
to inhibit generation of tp_clear. Thanks, looks ok to me. Please open a pull request on github for it. I reworked it a bit, pull request is here: https://github.com/cython/cython/pull/248 Sorry it took so long, real life takes it's toll ;-)
I think that name is as good as any. It could be "no_gc_clear", if you find that clearer. It hints at GC, at least. That's what I did. I think that should be part of the name somehow. Please also document it somewhere in the extension types doc section (in the user guide): https://github.com/cython/cython/blob/master/docs/src/userguide/extension_ty...
Done. Please advise if you think it needs improvement - I have a hard time to describe complex facts in concise form.
How should the decorator to completely disable GC for a class be called? @cython.nogc? +1 I did not yet implement this.
Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-312002-10 Fax: +49-(0)351-312002-29 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Stefan Behnel wrote:
Torsten Landschoff, 22.04.2013 13:07:
One could even think about building a graph of possible object relationships ... Slot refers only to Slots and Slots only to Context, so these can't build a cycle.
Interesting. Yes, that might work.
Only if subclassing of Slot and Context are forbidden. -- Greg
Greg Ewing, 23.04.2013 01:16:
Stefan Behnel wrote:
Torsten Landschoff, 22.04.2013 13:07:
One could even think about building a graph of possible object relationships ... Slot refers only to Slots and Slots only to Context, so these can't build a cycle.
Interesting. Yes, that might work.
Only if subclassing of Slot and Context are forbidden.
Right. Subtypes of a non-GC type can happily add attributes and start supporting cyclic garbage collection, including Python subclasses. So this only applies to "final" types and builtins. Not entirely uncommon, especially in the "keep this private thing alive until all referrers have died" use case, but I's say this restriction drops the priority a bit. Stefan
On 04/23/2013 08:01 AM, Stefan Behnel wrote:
Greg Ewing, 23.04.2013 01:16:
Only if subclassing of Slot and Context are forbidden. Right. Subtypes of a non-GC type can happily add attributes and start supporting cyclic garbage collection, including Python subclasses. So this only applies to "final" types and builtins. Not entirely uncommon, especially in the "keep this private thing alive until all referrers have died" use case, but I's say this restriction drops the priority a bit.
Does Cython have an equivalent of the "final class DoNoExtend { ... }" of the Java world? In any case, Greg has a good point. I seriously did not think about it just because I did not plan to derive from those classes. Greetings, Torsten -- DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH Torsten Landschoff Office Dresden Tel: +49-(0)351-4519587 Fax: +49-(0)351-4519561 mailto:torsten.landschoff@dynamore.de http://www.dynamore.de DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH Registration court: Stuttgart, HRB 733694 Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz
Torsten Landschoff, 23.04.2013 10:06:
On 04/23/2013 08:01 AM, Stefan Behnel wrote:
Greg Ewing, 23.04.2013 01:16:
Only if subclassing of Slot and Context are forbidden. Right. Subtypes of a non-GC type can happily add attributes and start supporting cyclic garbage collection, including Python subclasses. So this only applies to "final" types and builtins. Not entirely uncommon, especially in the "keep this private thing alive until all referrers have died" use case, but I's say this restriction drops the priority a bit.
Does Cython have an equivalent of the "final class DoNoExtend { ... }" of the Java world?
@cython.final cdef class ExtType: ... You can also declare a class @cython.internal to prevent it from showing up in the module dict. Stefan
participants (3)
-
Greg Ewing -
Stefan Behnel -
Torsten Landschoff