* Hrvoje Niksic, on 14.07.2010 10:17:
"Alf P. Steinbach /Usenet"<alf.p.steinbach+use...@gmail.com>  writes:

Also, things like the 'owned' option is just asking for trouble.

Isn't owned=true (or equivalent) a necessity when initializing from a
PyObject* returned by a function declared to return a "new reference"?

No, not quite.

Consider this signature (PyCXX):

   String( PyObject* pyob, bool owned = false )

versus this (cppy):

   PyString( PyPtr object )

With the first signature, every time you construct a String you have to remember to (explicitly or implicitly) set the bool flag correctly depending on where the actual argument value comes from.

With the second signature the /type/ of the actual argument decides, automatically, so there's much less room for messing things up.

With the second signature, if the actual argument is a raw PyObject* pointer then it's not owned, and the PyPtr formal argument doesn't increment the reference count but just takes ownership. If the actual argument, on the other hand, is a PyPtr, then the object is owned by the collection of PyPtr instances that refer to the object, and the new formal argument PyPtr instance then increments the reference count. In passing, if it should happen that the Python community uses the word 'owned' in the opposite sense of what's conventional in C++, then I guess & hope you'll figure out what I mean from this description.

PyPtr currently looks like this (complete code):


<code file="PyPtr.h">
// progrock.cppy  --  "C++ plus Python"
// A simple C++ framework for writing Python 3.x extensions.
//
// Copyright (c) Alf P. Steinbach, 2010.

#ifndef CPPY_PYPTR_H
#define CPPY_PYPTR_H
#include <progrock/cppx/devsupport/better_experience.h>


//----------------------------------------- Dependencies:

#include <Python.h>
#include <assert.h>
#include <algorithm>



//----------------------------------------- Interface:

namespace progrock{ namespace cppy {
    using namespace cppx;

    enum DoAddRef {};

    class PyPtr
    {
    private:
        PyObject*   p_;

    public:
        typedef cppy::DoAddRef  DoAddRef;

        PyPtr( PyObject* p = 0 ): p_( p ) {}

        PyPtr( PyObject* p, DoAddRef ): p_( p )
        {
            assert( p != 0 );  Py_INCREF( p_ );
        }

        PyPtr( PyPtr const& other ): p_( other.p_ ) { Py_XINCREF( p_ ); }

        ~PyPtr() { Py_XDECREF( p_ ); }

        void swapWith( PyPtr& other )   { std::swap( p_, other.p_ ); }
        PyPtr& operator=( PyPtr other ) { swapWith( other ); return *this; }

        PyObject* get() const           { return p_; }

        PyObject* release()
        {
            PyObject* const result  = p_;
            p_ = 0;
            return result;
        }
    };

    inline PyObject* withAddedRef( PyObject* p )
    {
        Py_INCREF( p );
        return p;
    }

    inline PyObject* pyNoneRef()
    {
        return withAddedRef( Py_None );
    }
} }  // namespace progrock::cppy


#endif
</code>


As you can see at the end there, there is 'withAddedRef' and 'pyNoneRef', and for that matter the 'DoAddRef' and the 'release()' method, for the cases where PyPtr default handling doesn't quite cut it... :-)


How does your API deal with the distinction between new and borrowed
references?

See above.

There are some cases where it must be dealt with, but the main idea is to encode that into /types/, instead of as context-dependent figure-it-out.

That's also the main idea of C++ as compared to C, to encode much more into types, which helps both for compile time error detection and for automating things (like above), which is Very Nice, but which also can make for enormous waste of time trying to make the darned language do what you want it to do! :-)


Cheers & hth.,

- Alf


Disclaimer: it's late in the day/night for me, so the above explanation may have big logic holes, mispelings and so on, but I hope it gives the idea.

--
blog at <url: http://alfps.wordpress.com>
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to