Re: [sage-devel] Problem with inheritance from two extension classes

129 views
Skip to first unread message

Robert Bradshaw

unread,
Mar 9, 2013, 3:28:35 AM3/9/13
to sage-devel, cython...@googlegroups.com
Ugh. Usually, multiple inheritance from extension types in Python (and
hence Cython) is prohibited because the base types have different
layouts, e.g.

class C(Integer, RealDoubleElement): pass
...:
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict

Here the class layouts are compatible, so no error on construction,
but the vtables are not. The simple solution is to simply disallow
such inheritance, supporting it dynamically would be tricky or
expensive (or both).

On Sat, Mar 9, 2013 at 12:05 AM, Simon King <simon...@uni-jena.de> wrote:
> Hi!
>
> Currently, I try to make homsets and morphisms compliant with what one
> would usually do when implementing parents and elements---in particular,
> the default __mul__ and __add__ should do something meaningful and should
> thus not be overridden. In particular, one would implement addition in
> subclasses by providing a method _add_, not __add__.
>
> But this implies a subtle problem, in
> sage.homology.chain_complex_morphism.ChainComplexMorphism.
>
> I guess one would like to define it as follows,
> class ChainComplexMorphism(Morphism, ModuleElement)
> because it is a morphism, on the one hand, but a module element, on the
> other hand.
>
> Both Morphism and ModuleElement are extension classes with their own cdef
> attributes/methods, but it *is* possible to inherit from both (Python
> does not throw an error, i.e., it does not complain about incompatible
> layouts).
>
> If one makes ChainComplexMorphism use the __add__ method inherited from
> ModuleElement, then eventually the line
> return (<ModuleElement>left)._add_(<ModuleElement>right)
> is executed. But "(<ModuleElement>left)._add_" returns a totally
> different cdef method, namely "(<Map>left)._update_slots"! Example:
>
> sage: cython("""
> ....: from sage.categories.map cimport Map
> ....: from sage.structure.element cimport ModuleElement
> ....: def test(a):
> ....: return <void*>((<ModuleElement>a)._add_) == <void *>((<Map>a)._update_slots)
> ....: """)
> sage: from sage.categories.map import Map
> sage: class C(Map, ModuleElement): pass
> ....:
> sage: test(a)
> True
> sage: a._add_(a)
> Traceback (most recent call last):
> ...
> ... in sage.structure.element.ModuleElement._add_ (sage/structure/element.c:9801)()
> ... in sage.categories.map.Map._update_slots (sage/categories/map.c:2633)()
> TypeError: 'C' object has no attribute '__getitem__'
>
> So, _add_ can not be accessed, and in particular one can not use the
> default __add__ (which is essential for using the coercion model) on a
> class that inherits from both Map and ModuleElement.
>
> Do you see a work around?
>
> I asked this question on the cython-users list, too (sorry for those who
> read both), but I think it is as much a question about sage than a
> question about cython.
>
> Best regards,
> Simon
>
>
> --
> 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+...@googlegroups.com.
> To post to this group, send email to sage-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sage-devel?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Robert Bradshaw

unread,
Mar 9, 2013, 3:30:44 AM3/9/13
to sage-devel, cython...@googlegroups.com

Simon King

unread,
Mar 9, 2013, 7:09:11 AM3/9/13
to cython...@googlegroups.com, sage-...@googlegroups.com
Hi Robert,

On 2013-03-09, Robert Bradshaw <robe...@math.washington.edu> wrote:
> Ugh. Usually, multiple inheritance from extension types in Python (and
> hence Cython) is prohibited because the base types have different
> layouts, ...

Ah, I thought they were incompatible, but Python just didn't realise.

> Here the class layouts are compatible, so no error on construction,
> but the vtables are not. The simple solution is to simply disallow
> such inheritance, supporting it dynamically would be tricky or
> expensive (or both).

OK. So, you suggest to make a bug report to Python, telling them to
check compatibility of vtables too, rather than only of the layouts? Or
is this something that can be dealt with on the side of Cython?

Concerning work-around:

- Is there a way to re-define ModuleElement and Map, so that their
respective c(p)def methods will not get confused when inheriting from
both?

If this question has a negative answer, then the (more Sage related)
question arises how else one can fit ChainComplexMorphism into Sage's
coercion framework:

- Should one perhaps generally derive Map from ModuleElement rather than
from Element, anticipating that some maps may be added and not just
composed? After all, if there is no addition, then one can simply raise
an error.
- Let ChainComplexMorphism inherit from ModuleElement only, providing a
custom __call__ and __mul__, duplicating code for morphisms?
- Let it inherit from Morphism (i.e., Map) only, providing a custom __add__,
or even try to get addition from the category framework?

Best regards,
Simon

Stefan Behnel

unread,
Mar 9, 2013, 7:35:52 AM3/9/13
to cython...@googlegroups.com
Simon King, 09.03.2013 13:09:
> On 2013-03-09, Robert Bradshaw wrote:
>> Ugh. Usually, multiple inheritance from extension types in Python (and
>> hence Cython) is prohibited because the base types have different
>> layouts, ...
>
> Ah, I thought they were incompatible, but Python just didn't realise.
>
>> Here the class layouts are compatible, so no error on construction,
>> but the vtables are not. The simple solution is to simply disallow
>> such inheritance, supporting it dynamically would be tricky or
>> expensive (or both).
>
> OK. So, you suggest to make a bug report to Python, telling them to
> check compatibility of vtables too, rather than only of the layouts?

CPython doesn't know anything about Cython's vtables, so there is nothing
it can do. This needs to be handled by Cython - somehow ...

Stefan

Volker Braun

unread,
Jun 19, 2013, 9:46:27 PM6/19/13
to sage-...@googlegroups.com, cython...@googlegroups.com
Simon, did you ever reach a conclusion? The same problem is in elliptic curves: A point is both a morphism from Spec(R) and an abelian group element. 

Simon King

unread,
Jun 20, 2013, 2:11:43 AM6/20/13
to cython...@googlegroups.com, sage-...@googlegroups.com
Hi Volker,

On 2013-06-20, Volker Braun <vbrau...@gmail.com> wrote:
> ------=_Part_2621_31539978.1371692787443
> Content-Type: text/plain; charset=ISO-8859-1
>
> Simon, did you ever reach a conclusion? The same problem is in elliptic
> curves: A point is both a morphism from Spec(R) and an abelian group
> element.

No, sorry. I worked on different things in the meantime.

Best regards,
Simon

mark florisson

unread,
Jun 20, 2013, 6:13:30 AM6/20/13
to cython...@googlegroups.com
Cython could use Dag's pyextensibletype to look up attributes
(allocated separately from the object) and methods, or (and this seems
like a worse idea) C++-like vtables:
http://www.phpcompiler.org/articles/virtualinheritance.html .

> --
>
> ---
> You received this message because you are subscribed to the Google Groups "cython-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages