<br><br><div><span class="gmail_quote">On 11/28/06, <b class="gmail_sendername">Talin</b> <<a href="mailto:talin@acm.org">talin@acm.org</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Guido van Rossum wrote:<br>> On 11/28/06, Talin <<a href="mailto:talin@acm.org">talin@acm.org</a>> wrote:<br>>> Guido van Rossum wrote:<br>>> > Some comments:<br>>> ><br>>> > - Fredrik's solution makes one call per registered method. (I don't
<br>>> > know if the patch he refers to follows that model.) That seems a fair<br>>> > amount of code for an average type -- I'm wondering if it's too early<br>>> > to worry about code bloat (I don't think the speed is going to
<br>>> > matter).<br>>><br>>> One other thought: The special constants could themselves be nothing<br>>> more than the offset into the PyTypeObject struct, i.e.:<br>>><br>>> #define SPECMETHOD_NEW ((const char*)offsetof(PyTypeObject,tp_new))
<br>><br>> I think this would cause too many issues with backwards compatibility.<br>><br>> I like the idea much better to use special names (e.g. starting with a<br>> ".").<br>><br>>> In the PyType_Ready code, you would see if the method name had a value
<br>>> of less than sizeof(PyTypeObject); If so, then it's a special method<br>>> name, and you fill in the struct at the specified offset.<br>>><br>>> So the interpretation of the table could be very simple and fast. It has
<br>>> a slight disadvantage from the approach of using actual string names for<br>>> special methods, in that it doesn't allow the VM to silently<br>>> promote/demote methods to 'special' status.<br>>
<br>> I think the interpretation will be fast enough (or else what you said<br>> about premature optimization earlier wouldn't be correct. :-)<br><br>OK, based on these comments and the other feedback from this thread,
<br>here's a more concrete proposal:<br><br>== Method Table ==<br><br>Method definitions are stored in a static table, identical in format to<br>the existing PyMethodDef table.<br><br>For non-method initializers, the most commonly-used ones will be passed
<br>in as parameters to the type creation function. Those that are less<br>commonly used can be written in as a secondary step after the type has<br>been created, or in some cases represented in the tp_members table.<br><br>
== Method Names ==<br><br>As suggested by Guido, we use a naming convention to determine how a<br>method in the method table is handled. I propose that methods be divided<br>into three categories, which are "Normal", "Special", and "Internal"
<br>methods, and which are interpreted slightly differently at type<br>initialization time.<br><br>* Internal methods are those that have no equivalent Python name, such<br>as tp_free/tp_alloc. Internal methods names start with a dot ("."), so
<br>tp_alloc would be represented by the string ".tp_alloc".</blockquote><div><br>Haven't we had various arguments about how it's bad to use a leading dot to have a special meaning? I understand why we need some way to flag internal methods on a type and I support going with an explicit way of specifying, but is a dot really the best solution? I mean something like INTERNAL_METH "tp_alloc" would even work using C's automatic string concatentation and doing::
<br><br> #define INTERNAL_METH "."<br><br>or whatever string we wanted that was not valid in a method name. I don't think this would lead us down the road of tons of macros and it makes things very visible.<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Internal methods are always stored into a slot in the PyTypeObject. If<br>there is no corresponding slot for a given name, that is a runtime error.
<br><br>* Special methods have the double-underscore (__special__) naming<br>convention. A special method may or may not have a slot definition in<br>PyTypeObject. If there is such a slot, the method pointer will be stored
<br>into it; If there is no such slot, then the method pointer is stored<br>into the class dict just like a normal method.<br><br>Because the decision whether to put the method into a slot is made by<br>the VM, the set of available slots can be modified in future Python
<br>releases without breaking existing code.<br><br>* Normal methods are any methods that are neither special or internal.<br>They are not placed in a slot, but are simply stored in the class dict.<br><br>Brett Cannon brought up the point about __getitem__ being ambiguous,
<br>since there are two slots, one for lists and one for mappings. This is<br>handled as follows:<br><br>The "mapping" version of __getitem__ is a special method, named<br>"__getitem__". The "list" version, however, is considered an internal
<br>method (since it's more specialized), and has the name ".tp_getitem".</blockquote><div><br>Or the other option is that in the future we just don't have the distinction and make sure that the __getitem__ methods do the requisite type checks. The type check is done at some point in the C code anyway so it isn't like there is a performance reason for the different slots. And as for providing a C-level function that provides a __getitem__ that takes Py_ssize_t, that can still be provided, it just isn't what is put into the struct.
<br><br>The one problem this does cause is testing for the interface support at the C level. But that could be a C function that looks for specific defined functions. Plus this would help make the C code less distinct from the way things expose themselves at the Python level (which I personally think is a good thing).
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Greg Ewing's point about "next" is handled as follows: A function named
<br>"next" will never be treated as a special method name, since it does not<br>follow the naming convention of either internal or special names.<br>However, if you want to fill in the "tp_next" slot of the PyTypeObject,
<br>you can use the string ".tp_next" rather than "next".<br><br>== Type Creation ==<br><br>For backwards compatibility, the existing PyType_Ready function will<br>continue to work on statically-declared PyTypeObject structures. A new
<br>function, 'PyType_Create' will be added that creates a new type from the<br>input parameters and the method initialization tables as described<br>previously. The actual type record may be allocated dynamically, as<br>
suggested by Greg Ewing.<br><br>Structures such as tp_as_sequence which extend the PyTypeObject will be<br>created as needed, if there are any methods that require those extension<br>structures.<br><br>== Backwards compatibility ==
<br><br>The existing PyType_Ready and C-style static initialization mechanism<br>will continue to work - the new method for type creation will coexist<br>alongside the old.<br><br>It is an open question as to whether PyType_Ready should attempt to
<br>interpret the special method names and fill in the PyTypeObject slots.<br>If it does, then PyType_Create can all PyType_Ready as a subroutine<br>during the type creation process.<br><br>Otherwise, the only modifications to the interpreter will be the
<br>creation of the new PyType_Create function and any required subroutines.<br>Existing code should be unaffected.</blockquote><div><br>Overall sounds good to me!<br><br>-Brett <br></div><br></div><br>