On Nov 12, 2008, at 2:31 AM, Nicolas M. Thiery wrote: > On Mon, Nov 10, 2008 at 07:13:58PM -0800, Robert Bradshaw wrote: >> If I understand your code correctly, what you're proposing is that to >> declare an Parent/Element to be a member of a category, one creates >> the category and then dynamically creates classes at runtime that >> need to be inherited from. Using QQ[x] as an example, I would create >> the category >> >> C = JoinCategory(EuclideanRings(), Algebras(QQ)) >> >> and then inherit from the dynamically created C.parent_class() and >> C.element_class(). > > That's the idea. But I see this as an implementation detail that the > average programmer should not have to play with.
Yes. Of course *I'm* very interested in the implementation details, now that we've decided what we mean by "category" and what we want to do with them, but I'm certainly in the minority there :). > So actually I have > modified the Parent.__init__ constructor to do this automatically for > you. See the Category documentation a bit lower in my patch on > sage-combinat; here is a short extract: > > We now construct a parent in the usual way: > > sage: from sage.categories.category import build_class > sage: class myparent(Parent): > ... def __init__(self): > ... Parent.__init__(self, categories=[Ds()]) > ... def g(self): > ... return "myparent" > ... class Element: > ... def method(self): > ... return "myparent" > sage: D = myparent() > sage: D.__class__ > <class '__main__.myparent_with_categories'> > > Something similar should be done for elements: the class would be > built automatically from the Element class of the categories and of > the parent itself. This is not implemented yet. > > Note that the classes created dynamically are cached. So most of the > time two parents coming from the same place (e.g. VectorSpace(3, QQ) > or VectorSpace(3, RR)) would share the same underlying class. > > One drawback: the current implementation uses a hack (which is well > localized but still a hack): the Parent.__init__(self) method changes > the class of self on the fly to the newly created one. How robust is > this, in particular w.r.t. cython class? It can't be done. sage: L = range(10) sage: L.__class__ = dict Traceback (most recent call last): ... TypeError: __class__ assignment: only for heap types Perhaps that's for the better, as treating a list as a dict would result in c-level incompatibilities and segfaults. Note that there are several Parents (not just elements) that are implemented in Cython as well. For Elements, we avoid calling the __init__ method altogether (as in many cases that Python call may be more expensive than the arithmetic itself). However this is implemented behind the scenes, I fully agree with you that the average programmer should just be able to inherit from Parent/Element (optionally?) specifying the category the Parent belongs to, and it should "just work" without having to know some extra incantation. On the note of making it easy to understand, what would people think of renaming Parent to SetObject or even just Set? This would clear up the very frequently asked question "what is a Parent?" to give it a more mathematically-grounded name. >> Actually, if I wanted to sit down and write my super-optimized QQ[x] >> (say, by wrapping FLINT) I'm not even sure how I'd go about doing >> that. It's also unclear how this would fit into the coercion model >> (where the cdef classes Element and Parent use on c-level methods >> and attributes for speed). But you do avoid needing to implement a >> __getattr__ method. > > Yup. I indeed don't know yet how this fits with pure cython classes > (but see my other post about subclasses of cython classes). I am > hoping that something semantically equivalent can be implemented, but > for this I need you. The main thing is: do you foresee any blocker for > this design to be adapted to cython classes one way or the other. Actual full multiple inheritance for cdef'd classes in Cython won't happen for a long time, if ever. This is due to major technical difficulties (C++ style multiple inheritance won't work, as it casts by actually adjusting the pointer, which breaks when passing in and out of the Python library with PyObject*, and it seems every other way of doing it incurs much more overhead on non-multiply inherited classes). However, if they types are compatible (e.g. one side is pure Python), then it just might be possible to implement multiple inheritance... What can be simulated much more easily is a (nearly arbitrary) lookup if nothing is found in the straight line hierarchy. This means that if we have A | \ B C | / D where the C-D inheritance is emulated, a method on C would not override a method on A as desired. (One could manually manipulate the mro, but this would change all instances of D.) But this may be sufficient, as C and B would likely not have a common ancestor. Note that issubclass(D, C) would be False, which might also have implications for binding methods, though probably not too hard to get around. - Robert --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://www.sagemath.org -~----------~----~----~----~------~----~------~--~---