#10963: More functorial constructions
-------------------------------------+-------------------------------------
       Reporter:  nthiery            |        Owner:  stumpc5
           Type:  enhancement        |       Status:  needs_review
       Priority:  major              |    Milestone:  sage-6.1
      Component:  categories         |   Resolution:
       Keywords:  days54             |    Merged in:
        Authors:  Nicolas M. Thiéry  |    Reviewers:  Simon King, Frédéric
Report Upstream:  N/A                |  Chapoton
         Branch:                     |  Work issues:
  public/ticket/10963                |       Commit:
   Dependencies:  #11224, #8327,     |  8045aa4a4b7ada735b3eb6055382f9b341a39f1e
  #10193, #12895, #14516, #14722,    |     Stopgaps:
  #13589, #14471, #15069, #15094,    |
  #11688, #13394, #15150, #15506     |
-------------------------------------+-------------------------------------

Comment (by nthiery):

 Replying to [comment:389 vbraun]:
 > You are parsing the "Finite" class name, I don't care if it is explicit
 using string tools/regexes or implicit looking for classes whose names
 match certain strings. The usual way is to provide a programmatic
 interface that sets up stuff in code. You should avoid using strings for
 program flow, and most certainly not use them for foundational material. I
 wouldn't care so much if we were talking about some implementation details
 in the combinat project, but you expect us to go around and teach others
 to use this. That better have a really good reason for the current
 interface. **Simple** would be something that follows usual patterns (even
 if its a few characters more). I don't see anything simple here, I see a
 bunch of trickery that is extremely hard to understand by looking at the
 code.
 >
 > And you don't need operations on axioms? I see a lot of weird stuff in
 this ticket where you use strings to do operations that would be much
 clearer if you had some object to represent the axiom. E.g.:
 > {{{
 > sage: FiniteFields()._without_axiom("Commutative")
 > }}}
 > vs.
 > {{{
 > sage: FiniteFields().without(Commutative())
 > sage: FiniteFields() - Commutative()
 > }}}

 I will change this example to {{{FiniteFields() + Commutative()}}} so
 as to speak of an operation which is clearly useful in real life.

 The syntax:
 {{{
     FiniteFields().Commutative()
 }}}

 has the following merits:

 - No need to import stuff. From a single entry point (e.g. the
   category of Fields()), you can explore all categories you can get
   from it by just following the flow of calling methods.

 - Want to know what are the available axioms? Well, constructing the
   subcategory of objects satisfying the Finite axiom is a natural
   operation on a category; therefore, in a standard OO pattern you
   find this operations along the other methods. Just use
   introspection:

   {{{
       sage: C = Monoids()
       sage: C.<tab>
   }}}

   (as pointed by Nils, you could refine this to recover exactly the
   axioms)

 - Tab completion naturally reduces to exactly those axioms that are
   applicable in the given context.

 - Which file implements the commutativity axiom? Use introspection:
   {{{
     sage: Monoids().Finite.__module__
     'sage.categories.sets_cat'
   }}}

 - Where is the documentation for the `Commutative` axiom? Use
 introspection:
   {{{
     sage: C = Monoids()
     sage: C.Finite?
   }}}

 - Somewhat unrelated, but since you asked elsewhere. How do you know
   which mixins get inserted when you use a given axiom? Use
   introspection::

     {{{
         sage: Groups().Finite().parent_class.mro()
         [sage.categories.finite_groups.FiniteGroups.parent_class,
          sage.categories.finite_monoids.FiniteMonoids.parent_class,
          sage.categories.groups.Groups.parent_class,
          sage.categories.monoids.Monoids.parent_class,
          sage.categories.finite_semigroups.FiniteSemigroups.parent_class,
          sage.categories.semigroups.Semigroups.parent_class,
          sage.categories.magmas.Unital.Inverse.parent_class,
          sage.categories.magmas.Magmas.Unital.parent_class,
          sage.categories.magmas.Magmas.parent_class,
 sage.categories.finite_enumerated_sets.FiniteEnumeratedSets.parent_class,
          sage.categories.enumerated_sets.EnumeratedSets.parent_class,
          sage.categories.finite_sets.FiniteSets.parent_class,
          sage.categories.sets_cat.Sets.parent_class,
 sage.categories.sets_with_partial_maps.SetsWithPartialMaps.parent_class,
          sage.categories.objects.Objects.parent_class,
          object]
     }}}


 Besides I would not want to use arithmetic for the operation of adding
 an axiom, since mathematically we would not write this using
 arithmetic either, but that's a minor detail.


 Yes there is a bit of complexity under the hood. Implementing a mixins
 mechanism in a language that does not support it natively means that
 you have to do some non trivial stuff. The internals of an interpreter
 are not simple either. It does not necessarily means that it's
 complicated to use in practice.

 <grin>
 Oh but right, in Python, methods and attributes are accessed by
 looking up for strings in the dictionary of the classes/objects.
 Overriding a method means inserting a string in a dictionary.  Yuck!
 Maybe we should not be using methods and attributes at all in our
 code?
 </grin>


 > Its an absolute no-brainer in Python to model **everything** with
 objects. If I have an object then I can tell immediately.  Lets keep it
 simple and explicit, yes. Shorter but non-discoverable is most certainly
 not simpler. And explicit is better than implicit, as always.

 The axiom is basically already modeled by a *method*. That's rather
 simple and explicit. And introspection works rather naturally.

 Maybe we could go a bit further and indeed use objects instead of
 strings in the _with(...) methods and in the output of .axioms(). But
 please, go ahead, try it in a non trivial project and see if it really
 makes things easier to use in practice. It's not clear.

 I am happy leaving a note that this piece of the design is an
 implementation detail and subject to refactoring.

 > Also, I don't agree with atomicity in setting
 `_base_category_class_and_axiom` buys us anything. Its private by
 convention, so it is the job of the setter to make changes atomically if
 necessary (though thats hardly an issue in Python). But in multi-threaded
 Java, say, this would be a bad data structure as well. We all know the old
 joke, whats the only data structure in Cobol? A 2000-character EBCDIC
 string...

 <getting frustrated>
 Whatever. That's a minor implementation detail I don't care about. Not
 happy with it? Go ahead, fix it and get everything right. I spent
 weeks polishing everything to a state where it works smoothly. This
 patch has been advertised for quite some time now, and already got
 positively reviewed featurewise months ago. Time to move on.
 </getting frustrated>

                       Nicolas

--
Ticket URL: <http://trac.sagemath.org/ticket/10963#comment:397>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to