<br><br><div><span class="gmail_quote">On 11/28/06, <b class="gmail_sendername">Talin</b> &lt;<a href="mailto:talin@acm.org">talin@acm.org</a>&gt; 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>&gt; On 11/28/06, Talin &lt;<a href="mailto:talin@acm.org">talin@acm.org</a>&gt; wrote:<br>&gt;&gt; Guido van Rossum wrote:<br>&gt;&gt; &gt; Some comments:<br>&gt;&gt; &gt;<br>&gt;&gt; &gt; - Fredrik's solution makes one call per registered method. (I don't
<br>&gt;&gt; &gt; know if the patch he refers to follows that model.) That seems a fair<br>&gt;&gt; &gt; amount of code for an average type -- I'm wondering if it's too early<br>&gt;&gt; &gt; to worry about code bloat (I don't think the speed is going to
<br>&gt;&gt; &gt; matter).<br>&gt;&gt;<br>&gt;&gt; One other thought: The special constants could themselves be nothing<br>&gt;&gt; more than the offset into the PyTypeObject struct, i.e.:<br>&gt;&gt;<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp; #define SPECMETHOD_NEW ((const char*)offsetof(PyTypeObject,tp_new))
<br>&gt;<br>&gt; I think this would cause too many issues with backwards compatibility.<br>&gt;<br>&gt; I like the idea much better to use special names (e.g. starting with a<br>&gt; &quot;.&quot;).<br>&gt;<br>&gt;&gt; In the PyType_Ready code, you would see if the method name had a value
<br>&gt;&gt; of less than sizeof(PyTypeObject); If so, then it's a special method<br>&gt;&gt; name, and you fill in the struct at the specified offset.<br>&gt;&gt;<br>&gt;&gt; So the interpretation of the table could be very simple and fast. It has
<br>&gt;&gt; a slight disadvantage from the approach of using actual string names for<br>&gt;&gt; special methods, in that it doesn't allow the VM to silently<br>&gt;&gt; promote/demote methods to 'special' status.<br>&gt;
<br>&gt; I think the interpretation will be fast enough (or else what you said<br>&gt; 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 &quot;Normal&quot;, &quot;Special&quot;, and &quot;Internal&quot;
<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 (&quot;.&quot;), so
<br>tp_alloc would be represented by the string &quot;.tp_alloc&quot;.</blockquote><div><br>Haven't we had various arguments about how it's bad to use a leading dot to have a special meaning?&nbsp; 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?&nbsp; I mean something like INTERNAL_METH &quot;tp_alloc&quot; would even work using C's automatic string concatentation and doing::
<br><br>&nbsp; #define INTERNAL_METH &quot;.&quot;<br><br>or whatever string we wanted that was not valid in a method name.&nbsp; 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 &quot;mapping&quot; version of __getitem__ is a special method, named<br>&quot;__getitem__&quot;. The &quot;list&quot; version, however, is considered an internal
<br>method (since it's more specialized), and has the name &quot;.tp_getitem&quot;.</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.&nbsp; 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.&nbsp; 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.&nbsp; But that could be a C function that looks for specific defined functions.&nbsp; 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 &quot;next&quot; is handled as follows: A function named
<br>&quot;next&quot; 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 &quot;tp_next&quot; slot of the PyTypeObject,
<br>you can use the string &quot;.tp_next&quot; rather than &quot;next&quot;.<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>