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
-~----------~----~----~----~------~----~------~--~---

Reply via email to