Should the "Element = ..." trick require categories?

112 views
Skip to first unread message

Jeroen Demeyer

unread,
Dec 9, 2017, 3:45:01 AM12/9/17
to sage-devel
The "modern" way to define a Parent class is as follows:

class MyParent(Parent):
Element = MyElement
def __init__(self):
Parent.__init__(self, category=MyCategory())

One thing which surprises me is that the code to have the "Element =
MyElement" trick work is implemented in the category of Sets. It seems
to me that this should really be part of the general Parent
infrastructure, independent of categories.

So, is there any particular reason why this is implemented in Sets? Are
there any objections to changing that?


Jeroen.

Travis Scrimshaw

unread,
Dec 10, 2017, 9:39:51 AM12/10/17
to sage-devel
My guess is so that one could define an _element_constructor_ at the category level. Although IMO, the possibility of that being meaningful is low considering you have to know something about the implementation of the associated element class in order to do this, which breaks the abstract-ness of the category code. There is one very natural exception to this: façade parents, which is a category-level implementation/property. So you will have to address this, but my current impression from reading the code is the current indirection is not necessary.

Best,
Travis

Jeroen Demeyer

unread,
Dec 10, 2017, 12:34:39 PM12/10/17
to sage-...@googlegroups.com
On 2017-12-10 15:39, Travis Scrimshaw wrote:
> My guess is so that one could define an _element_constructor_ at the
> category level.

I see. The problem is that the category comes after Parent in the MRO,
right? So if Parent implements _element_constructor_, then the category
cannot.

Nicolas M. Thiery

unread,
Dec 10, 2017, 4:29:09 PM12/10/17
to sage-...@googlegroups.com
Hi Jeroen,
As far as I remember, it's stipulated that any Parent should be in
Sets. So, like for many other features, it's possible in principle to
implement them equivalently in Parent or Sets.ParentMethods. The
latter tends to be more flexible (e.g. a subcategory can override it).

Is there a use case where having this in Parent would be preferable?

Cheers,
Nicolas
--
Nicolas M. Thiéry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/

Travis Scrimshaw

unread,
Dec 10, 2017, 9:17:32 PM12/10/17
to sage-devel
There are two things going on that I had thought were coupled together, but are actually not:

1 - The construction of the dynamic class element_class, which is currently done by Parent.__make_element_class__, which in turn indirectly calls Category._make_named_class via @lazy_attribute Category.element_class via @lazy_attribute _abstract_element_class.
2 - The initialization of a default _element_constructor_ method, which is done mostly in the category but there is some logic in Parent to set this (that should fundamentally be removed).

So everything I said above is primarily focused on 2, whereas the main issue is 1 and is separate from 2.


Is there a use case where having this in Parent would be preferable?

My impression of the general idea is to consolidate and simplify the logic to make maintenance easier. I do not think we would get much of a speed benefit because constructing the element class should only be done once. Although I do not see a reason why a subcategory would want to override _make_named_class or have a specific element_class (to me, this breaks the abstraction that categories are support to have).

Part of me would like to see this logic in Element, where it dynamically changes/sets its class upon creation. That way, we could simply create an elissueement class of any type and still retain the category information, so we could easily have homsets with multiple element classes. Unfortunately I think this would significantly slow down element creation as all of this class and category information would have to be processed on every creation.

Since the element_class is really something that is used by the parent, IMO it is better to be in Parent than in the category. I also think if we can streamline some of this code, it will be easier to construct multiple element classes for a given parent.

Best,
Travis

Jeroen Demeyer

unread,
Dec 11, 2017, 7:15:13 AM12/11/17
to sage-...@googlegroups.com
On 2017-12-10 22:29, Nicolas M. Thiery wrote:
> As far as I remember, it's stipulated that any Parent should be in
> Sets.

I don't think that this is stipulated somewhere. I also feel that this
shouldn't be a hard requirement. I think that the low-level basic stuff
(I consider creating elements amongst that) should work without
categories and that categories should only be used for additional
functionality on top of that.

> Is there a use case where having this in Parent would be preferable?

I can think of two reasons: the first is efficiency. Implementing stuff
in Parent is faster than doing it in categories. Second (as Travis also
said), creating elements is partially implemented in Parent and
partially in Sets. This is quite confusing and it would be best to do
this in one place.


Jeroen.

Simon King

unread,
Dec 11, 2017, 7:32:01 AM12/11/17
to sage-...@googlegroups.com
Hi Jeroen,

On 2017-12-11, Jeroen Demeyer <jdem...@cage.ugent.be> wrote:
> On 2017-12-10 22:29, Nicolas M. Thiery wrote:
>> As far as I remember, it's stipulated that any Parent should be in
>> Sets.
>
> I don't think that this is stipulated somewhere.

I think I stated it in the thematic tutorial on "how to implement new
algebraic structures".

> I also feel that this shouldn't be a hard requirement.

I think it should! For category objects that are not sets, one should
use CategoryObject. For user-visible objects in Sage that haven't
anything to do with categories, one should use SageObject. And for
everything else, Python gave us <object>.

> I think that the low-level basic stuff
> (I consider creating elements amongst that) should work without
> categories and that categories should only be used for additional
> functionality on top of that.

Except if the basic functionality refers to category stuff. Element
creation does!

>> Is there a use case where having this in Parent would be preferable?
>
> I can think of two reasons: the first is efficiency.

+1, although currently I don't know an example where this actually
results in a noticeable problem. A couple of years ago though, it
was a serious bottleneck.

> Second (as Travis also
> said), creating elements is partially implemented in Parent and
> partially in Sets. This is quite confusing and it would be best to do
> this in one place.

+100. I think the current implementation has too many levels of
indirection and too many hooks for the implementation of a single
functionality.

Cheers,
Simon

Jeroen Demeyer

unread,
Dec 11, 2017, 12:10:42 PM12/11/17
to sage-...@googlegroups.com
On 2017-12-11 13:31, Simon King wrote:
> Except if the basic functionality refers to category stuff. Element
> creation does!

Can you elaborate on this? In the case where a Parent has an
element_class attribute, why should element creation involve categories?

I agree that it should still be *possible* to implement element
construction in the category, but it should not be *required*.

Simon King

unread,
Dec 11, 2017, 12:36:30 PM12/11/17
to sage-...@googlegroups.com
Hi Jeroen,

On 2017-12-11, Jeroen Demeyer <jdem...@cage.ugent.be> wrote:
> On 2017-12-11 13:31, Simon King wrote:
>> Except if the basic functionality refers to category stuff. Element
>> creation does!
>
> Can you elaborate on this? In the case where a Parent has an
> element_class attribute, why should element creation involve categories?

Well, we want to mix in P.category().element_class (an abstract class)
into whatever P prescribes for its elements. So, P.element_class
should be a class whose mro also contains abstract element classes
defined in the category.

What I did not say is that the mechanism to construct the element class
of P should be coded in the category framework.

Best regards,
Simon

Jeroen Demeyer

unread,
Dec 12, 2017, 2:06:35 AM12/12/17
to sage-...@googlegroups.com
On 2017-12-11 18:35, Simon King wrote:
> Well, we want to mix in P.category().element_class (an abstract class)
> into whatever P prescribes for its elements. So, P.element_class
> should be a class whose mro also contains abstract element classes
> defined in the category.
>
> What I did not say is that the mechanism to construct the element class
> of P should be coded in the category framework.

Maybe you are misunderstanding me. I am *not* talking about determining
the element class. I talking about the mechanism, *given* the element
class, to *construct* instances of that class.

Erik Bray

unread,
Dec 12, 2017, 8:48:22 AM12/12/17
to sage-devel
I agree that an abstraction of the general mechanism could be
implemented in one place. For example there's no reason I can see
that Category._make_named_class needs to be in Category. It's already
written in a pretty abstract manner.
Reply all
Reply to author
Forward
0 new messages