Let me be completely explicit. This is inheritance: class Base(Parent): pass
class Derived(Base): pass Now we can put (instances of) them into arbitrary categories: class Base(Parent): def __init__(self): Parent.__init__(category=C1) class Derived(Base): def __init__(self): Parent.__init__(category=C2) Now instances of Derived (actually, Derived_with_category) end up with all the methods of Base and all the C2.ParentMethods, but not with C1.ParentMethods. The category is just not part of what is inherited. That is why I keep stressing that categories are not inheritance. If you could define Derived as class Derived(Base_with_category) then it would be inheritance, but that does not and should not work. At the end of the day, the category example is just a fancier version of class Base(Parent): def __init__(self): self.category=C1 class Derived(Base): def __init__(self): self.category=C2 which is called object composition, and not object inheritance. And that is the whole point of the category framework; Stuffing every object into a single inheritance hierarchy is inherently difficult to construct and maintain. This general software engineering principle doesn't have anything to do with math, it is a common insight that programmers from various fields have arrived at. The general solution, regardless of the programming language, is to provide components (categories) which you can combine arbitrarily to provide functionality to new classes through composition. On Saturday, September 14, 2013 10:58:01 PM UTC+1, Simon King wrote: > Actually, if the base class is a Python class, then the category framework > provides a (dynamic) Python class, and all what I stated above is just > *the same as* inheritance in Python. Thats just an implementation detail, one could have just used __getattr__ all the way if it weren't for the bad performance. Since you cannot inherit from Base_with_category in a derived class, the dynamic class doesn't actually play any role in the object hierarchy that one is building. They are strictly auxiliary, and are never inherited by any other class outside of the category implementation. > Coming back to the original question, should something be implemented as > > method of RingElement or as Rings.ElementMethod? Often, both is > feasible. > > I would actually *recommend* to do both at the same time in *most* cases: > Work on top of the base classes in sage.structure, and then initialise the > category framework for your parent and element. > Having to copy & paste a method between sage.structure and sage.category sounds like an obvious code smell to me. Instead, I would just enforce that elements of Rings() inherit from RingElement through the TestSuite, that kind of enforcing of internal consistency is one of the design goals of the category framework after all. Then there is no question about duplicate implementation: If a method is implemented RingElements then it would override any Rings().ElementMethod, so there is no point in copying it. > Also, you lose Cython > > type checking since you can only check for Cython classes. > > What?? Python can check types as well (isinstance). Python can do Python type checks, but Cython can do cpdef RingElement _mul_(self, RingElement right): in addition which does the check even before the _mul_ function is entered. And that you can't do in Python. -- You received this message because you are subscribed to the Google Groups "sage-devel" group. To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+unsubscr...@googlegroups.com. To post to this group, send email to sage-devel@googlegroups.com. Visit this group at http://groups.google.com/group/sage-devel. For more options, visit https://groups.google.com/groups/opt_out.