The Case For Do-Once

  • Thread starter Lawrence D'Oliveiro
  • Start date
L

Lawrence D'Oliveiro

I wrote my first Python extension library over the last couple of weeks. I
took note of all the recommendations to keep track of reference counts, to
ensure that objects were not disposed when they shouldn’t be, and were when
they should. However, the example code seems to use gotos. And the trouble
with these is that they don’t nest and un-nest easily; try to do too much
refactoring with them, and you run into the age-old “spaghetti codeâ€
problem.

Which is where the do-once block comes in. The basic control flow is this:
* Unconditionally initialize all dynamic storage to nil
* Do the main body of the code, aborting in any error
* Regardless of success or failure of the above, dispose of all
allocated dynamic storage, using disposal calls which turn into
noops if passed pointers that are already nil.

For example, here’s a utility routine from my extension that, passed a
Python array object, returns the address and length of the storage:

static void GetBufferInfo
(
PyObject * FromArray,
unsigned long * addr,
unsigned long * len
)
/* returns the address and length of the data in a Python array object. */
{
PyObject * TheBufferInfo = 0;
PyObject * AddrObj = 0;
PyObject * LenObj = 0;
do /*once*/
{
TheBufferInfo = PyObject_CallMethod(FromArray, "buffer_info", "");
if (TheBufferInfo == 0)
break;
AddrObj = PyTuple_GetItem(TheBufferInfo, 0);
LenObj = PyTuple_GetItem(TheBufferInfo, 1);
if (PyErr_Occurred())
break;
Py_INCREF(AddrObj);
Py_INCREF(LenObj);
*addr = PyInt_AsUnsignedLongMask(AddrObj);
*len = PyInt_AsUnsignedLongMask(LenObj);
if (PyErr_Occurred())
break;
}
while (false);
Py_XDECREF(AddrObj);
Py_XDECREF(LenObj);
Py_XDECREF(TheBufferInfo);
} /*GetBufferInfo*/

You can pretty much determine by inspection that all the reference counts
are properly maintained, no need to trace through convoluted flows of
control.
 
S

Stefan Behnel

Lawrence D'Oliveiro, 08.02.2010 09:53:
I wrote my first Python extension library over the last couple of weeks. I
took note of all the recommendations to keep track of reference counts, to
ensure that objects were not disposed when they shouldn’t be, and were when
they should.

This sounds more like a case for Cython to me, should have saved you a lot
of time.

Stefan
 
L

Lawrence D'Oliveiro

The basic control flow is this:
* Unconditionally initialize all dynamic storage to nil
* Do the main body of the code, aborting in any error
* Regardless of success or failure of the above, dispose of all
allocated dynamic storage, using disposal calls which turn into
noops if passed pointers that are already nil.

For more examples, see the spuhelper.c module here
<http://github.com/ldo/dvd_menu_animator>.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top