From: Ian Collins on
On 07/10/10 03:52 AM, Alf P. Steinbach /Usenet wrote:
> [Cross-posted comp.lang.python and comp.lang.c++]
>
> I lack experience with shared libraries in *nix and so I need to ask...
>
> This is about "cppy", some support for writing Python extensions in C++
> that I just started on (some days ago almost known as "pynis" (not funny
> after all)).
>
> For an extension module it seems that Python requires each routine to be
> defined as 'extern "C"'. And although e.g. MSVC is happy to mix 'extern
> "C"' and C++ linkage, using a routine declared as 'static' in a class as
> a C callback, formally they're two different kinds, and I seem to recall
> that /some/ C++ compiler balks at that kind of mixing unless specially
> instructed to allow it. Perhaps it was the Sun compiler?

Yes, it will (correctly) issue a warning.

As the is a bit OT, contact me directly and we can work through it. I
have had similar fun and games adding PHP modules!

--
Ian Collins
From: Alf P. Steinbach /Usenet on
* Ian Collins, on 09.07.2010 23:22:
> On 07/10/10 03:52 AM, Alf P. Steinbach /Usenet wrote:
>> [Cross-posted comp.lang.python and comp.lang.c++]
>>
>> I lack experience with shared libraries in *nix and so I need to ask...
>>
>> This is about "cppy", some support for writing Python extensions in C++
>> that I just started on (some days ago almost known as "pynis" (not funny
>> after all)).
>>
>> For an extension module it seems that Python requires each routine to be
>> defined as 'extern "C"'. And although e.g. MSVC is happy to mix 'extern
>> "C"' and C++ linkage, using a routine declared as 'static' in a class as
>> a C callback, formally they're two different kinds, and I seem to recall
>> that /some/ C++ compiler balks at that kind of mixing unless specially
>> instructed to allow it. Perhaps it was the Sun compiler?
>
> Yes, it will (correctly) issue a warning.
>
> As the is a bit OT, contact me directly and we can work through it. I
> have had similar fun and games adding PHP modules!

Thanks. I'm mailing you a zip with the code... <g>

The question, of course, whether it works in *nix.


Cheers,

- Alf

--
blog at <url: http://alfps.wordpress.com>
From: Robert Kern on
On 7/13/10 2:34 AM, Alf P. Steinbach /Usenet wrote:

> PS: You (the reader) may be wondering, why why why Yet Another Python/C++
> binding? Well, because I had this great name for it, "pyni", unfortunately
> already in use. But cppy is very different from Boost: Boost is large, cppy is
> tiny; Boost has as main goal to expose arbitrary C++ code to Python, automating
> argument conversion etc., while with cppy your Python design is exposed to C++
> with no enforced arg conversions and such; Boost relies on canned magic,
> difficult to subvert when it doesn't do what you want, while with cppy you are
> (or, so far, I am) in control; and I suspect that the Boost Python binding,
> relying on dynamic registries and stuff, is not all that efficient, while cppy
> is as efficient as using the Python C API to create an extension. And besides,
> cppy supports national characters in doc strings etc. And I'm Norwegian. So. :-)

Note that Boost is not the only C++ binding out there. You may want to take a
look at the old SCXX library, which appears to be similar in intent:

http://davidf.sjsoft.com/mirrors/mcmillan-inc/scxx.html

matplotlib uses it heavily, and their included copy may include some more recent
bugfixes and enhancements:

http://matplotlib.sourceforge.net/

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

From: Alf P. Steinbach /Usenet on
* Robert Kern, on 13.07.2010 17:16:
> On 7/13/10 2:34 AM, Alf P. Steinbach /Usenet wrote:
>
>> PS: You (the reader) may be wondering, why why why Yet Another Python/C++
>> binding? Well, because I had this great name for it, "pyni", unfortunately
>> already in use. But cppy is very different from Boost: Boost is large, cppy is
>> tiny; Boost has as main goal to expose arbitrary C++ code to Python, automating
>> argument conversion etc., while with cppy your Python design is exposed to C++
>> with no enforced arg conversions and such; Boost relies on canned magic,
>> difficult to subvert when it doesn't do what you want, while with cppy you are
>> (or, so far, I am) in control; and I suspect that the Boost Python binding,
>> relying on dynamic registries and stuff, is not all that efficient, while cppy
>> is as efficient as using the Python C API to create an extension. And besides,
>> cppy supports national characters in doc strings etc. And I'm Norwegian. So. :-)
>
> Note that Boost is not the only C++ binding out there. You may want to
> take a look at the old SCXX library, which appears to be similar in intent:
>
> http://davidf.sjsoft.com/mirrors/mcmillan-inc/scxx.html
>
> matplotlib uses it heavily, and their included copy may include some
> more recent bugfixes and enhancements:
>
> http://matplotlib.sourceforge.net/

Thanks! It seems that SCXX does those things that I've been planning to do but
haven't got around to (wrapping standard Python types), while what it doesn't do
(abstracting away all those tables etc. and mapping Python calls to C++ calls)
is what I've been working on. Which could be a Very Nice combination except that
I'm assuming Py3, while SCXX seems to be Py2 only. :-(


Cheers,

- Alf

--
blog at <url: http://alfps.wordpress.com>
From: Alf P. Steinbach /Usenet on
* Hrvoje Niksic, on 14.07.2010 10:17:
> "Alf P. Steinbach /Usenet"<alf.p.steinbach+usenet(a)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>