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.

Reply via email to