
On 28 September 2017 at 08:27, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 27 September 2017 at 19:28, Ivan Levkivskyi <levkivskyi@gmail.com> wrote:
If an object that is not a class object appears in the bases of a class definition, the ``__subclass_base__`` is searched on it. If found, it is called with the original tuple of bases as an argument. If the result of the call is not ``None``, then it is substituted instead of this object. Otherwise (if the result is ``None``), the base is just removed. This is necessary to avoid inconsistent MRO errors, that are currently prevented by manipulations in ``GenericMeta.__new__``. After creating the class, the original bases are saved in ``__orig_bases__`` (currently this is also done by the metaclass).
How would you feel about calling it "__mro_entry__", as a mnemonic for "the substitute entry to use instead of this object when calculating a subclass MRO"?
I don't have any preferences for the name, __mro_entry__ sounds equally OK to me. I think the other thing that needs to be clarified is whether or not
the actual metaclass can expect to receive an already-resolved sequence of MRO entries as its list of bases, or if it will need to repeat the base resolution process executed while figuring out the metaclass.
There are three points for discussion here: 1) It is necessary to make the bases resolution soon, before the metaclass is calculated. This is why I do this at the beginning of __build_class__ in the reference implementation. 2) Do we need to update type.__new__ to be able to accept non-classes as bases? I think no. One might be a bit surprised that class C(Iterable[int]): pass works, but type('C', (Iterable[int],), {}) fails with a metaclass conflict, but I think it is natural that static typing and dynamic class creation should not be used together. I propose to update ``type.__new__`` to just give a better error message explaining this. 3) Do we need to update types.new_class and types.prepare_class? Here I am not sure. These functions are rather utility functions and are designed to mimic in Python what __build_class__ does in C. I think we might add types._update_bases that does the same as its C counterpart. Then we can update types.new_class and types.prepare_class like you proposed, this will preserve their current API while types.new_class will match behaviour of __build_class__ If you and others agree with this, then I will update the PEP text and the reference implementation. Thanks for comments! -- Ivan