<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Jan 7, 2014 at 7:07 PM, Larry Hastings <span dir="ltr"><<a href="mailto:larry@hastings.org" target="_blank">larry@hastings.org</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF" text="#000000">
    <div dir="ltr"><div class="im"><br>
      <br>
      On 01/07/2014 03:38 PM, Brett Cannon wrote:<br>
      </div><div class="gmail_extra">
        <blockquote type="cite">
          <div class="gmail_quote"><div class="im">On Tue, Jan 7, 2014 at 6:24 PM, Larry
            Hastings <span dir="ltr"><<a href="mailto:larry@hastings.org" target="_blank">larry@hastings.org</a>></span>
            wrote:<br>
            </div><div class="im"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
              <div bgcolor="#FFFFFF" text="#000000">
                <div>For what it's worth, if we use the
                  "accumulator" approach I propose that the generated
                  code doesn't go at the very end of the file.  Instead,
                  I suggest they should go *near* the end, below the
                  implementations of the module / class methods, but
                  above the methoddef/type structures and the module
                  init function.<br>
                </div>
              </div>
            </blockquote>
            <div><br>
            </div>
            <div>If it is accumulated in a single location should it
              just be a single block for everything towards the end?
              Then forward declarations would go away (you could still
              have it as a comment to copy-and-paste where you define
              the implementation) and you can have a single macro for
              the PyMethodDef values, each class, etc. If you
              accumulated the PyMethodDef values into a single macro it
              would help make up for the convenience lost of converting
              a function by just cutting the old call signature up to
              the new *_impl() function.<br>
            </div>
          </div></div>
        </blockquote>
        <br>
        I *think* that would complicate some use cases.  People
        occasionally call these parsing functions from other functions,
        or spread their methoddef / typeobject structures throughout the
        file rather than putting them all at the end.<br>
        <br>
        I'm proposing that the blob of text immediately between the
        Clinic input and the body of the impl contain (newlines added
        here for clarity):<br>
        <blockquote>static char *parsing_function_doc;<br>
          <br>
          static PyObject *<br>
          parsing_function(...);<br>
          <br>
          #define PARSING_FUNCTION_METHODDEF \<br>
              { ... }<br>
          <br>
          static PyObject *<br>
          parsing_function_impl(...)<br>
        </blockquote>
        Then the "accumulator" would get the text of the docstring and
        the definition of the parsing_function.<br>
        <br>
        <br>
        On the other hand, if we wanted to take this opportunity to
        force everyone to standardize (all methoddefs and typeobjects go
        at the end!) we could probably make it work with one giant block
        near the end.<br>
        <br>
        Or I could make it flexible on what went into the accumulator
        and what went into the normal output block, and the default
        could be everything-in-the-accumulator.  Making the common easy
        and the uncommon possible and all that.  Yeah, that seems best.<br></div></div></div></blockquote><div><br></div><div>So let's make this idea concrete to focus a possible discussion. Using the example from the Clinic HOWTO and converting to how I see it working:</div>

<div><br></div><div>####################</div><div><br></div><div><div>/*[clinic input]</div><div>pickle.Pickler.dump</div><div><br></div><div>    obj: 'O'</div><div>        The object to be pickled.</div><div>    /</div>

<div><br></div><div>Write a pickled representation of obj to the open file.</div><div>[clinic start generated code]*/</div><div><br></div><div>static PyObject *</div><div>pickle_Pickler_dump_impl(PyObject *self, PyObject *obj)</div>

<div>/*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/</div><div>{</div><div>    /* Check whether the Pickler was initialized correctly (issue3664).</div><div>       Developers often forget to call __init__() in their subclasses, which</div>

<div>       would trigger a segfault without this check. */</div><div>    if (self->write == NULL) {</div><div>        PyErr_Format(PicklingError,</div><div>                     "Pickler.__init__() was not called by %s.__init__()",</div>

<div>                     Py_TYPE(self)->tp_name);</div><div>        return NULL;</div><div>    }</div><div><br></div><div>    if (_Pickler_ClearBuffer(self) < 0)</div><div>        return NULL</div><div>    ...</div>

</div><div>}</div><div><br></div><div>...</div><div><br></div><div>/*[clinic accumulate]*/</div><div><div>PyDoc_STRVAR(pickle_Pickler_dump__doc__,</div><div>"Write a pickled representation of obj to the open file.\n"</div>

<div>"\n"</div><div><br></div><div>static PyObject *</div><div>_pickle_Pickler_dump(PyObject *args)<br></div><div>{</div><div>  ...</div><div>  return pickle_Pickler_dump_impl(...);</div><div>}</div><div><br></div>

</div><div><div>#define _PICKLE_PICKLER_DUMP_METHODDEF    \</div><div>{"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__},</div></div><div><br></div><div>... any other pickler.Pickler Clinic stuff that does not directly involve the the impl function ...</div>

<div><br></div><div>#define _PICKLE_PICKLER_METHODDEF_ACCUMULATED  \</div><div>  _PICKLE_PICKLER_DUMP_METHODDEF  \</div><div>  ... any other MethodDef entries for pickle.Pickler</div><div><br></div><div>/*[clinic end accumulate: checksum=0123456789]*/</div>

<div><br></div><div>... pickle.Pickler struct where _PICKLE_PICKLER_METHODDEF_ACCUMULATED is all that is needed for the non-magical class methods ...</div><div><br></div><div><br></div><div>###########################</div>

<div><br></div><div><br></div><div>Another potential perk of doing a gathering of Clinic output is that if we take it to it's logical conclusion, then you can start to do things like define a method like pickle.Pickler.__init__, etc., have Clinic handle docstrings for modules and classes, and then it can end up spitting out the type struct entirely for you, negating the typical need to do all of that by hand (I don't know about the rest of you but I always just copy and paste that struct anyway, so having a tool slot in the right method names for the right positions would save me busy work). It could then go as far as then spit out the module initialization function definition line and then all you would need to do is fill that in; Clinic could handle all other module-level details for you in the very common case.</div>

</div></div></div>