best "void" return of a member function

A

Andreas Otto

Hi,

I'm writing a native language binding for a library.

http://libmsgque.sourceforge.net/

Every native method called by PYTHON have to return
a PyObject* even if the function itself does not
return anything.

I have 2 possibilities for return a PyObject*


1. the first argument of the method function
-> return self;
2. an entire new empty object
-> return Py_BuildValue("");

Question: what is the best return statement for a "void" function ?

P.S: NULL is not allowed, because NULL is returned in the case
of an "error"


mfg

Andreas Otto
 
A

Andreas Otto

Andreas Otto wrote:

well propable found the answer by my own ...

Py_RETURN_NONE

should be the best
 
S

Stefan Behnel

Andreas said:
I'm writing a native language binding for a library.

http://libmsgque.sourceforge.net/

Every native method called by PYTHON have to return
a PyObject* even if the function itself does not
return anything.
[...]
Question: what is the best return statement for a "void" function ?

Hmmm, this sounds like your goal is to write an exact 1:1 wrapper of the C
library API (for which there are tools like SWIG&friends). If the library
happens to have a rather unusual, close-to object oriented, high-level C API,
that might work. Otherwise, you might want to try to wrap it in a more Pythonic
look&feel style, that wraps operations and use-cases rather than plain
functions. That should make it easier to hide things like memory allocation and
other C implementation details from users, and will generally increase the
performance of your binding, as it will require less calls for larger operations
in C space.

Stefan
 
S

Stefan Behnel

Stefan said:
you might want to try to wrap it in a more Pythonic
look&feel style, that wraps operations and use-cases rather than plain
functions. That should make it easier to hide things like memory allocation
and other C implementation details from users, and will generally increase
the performance of your binding, as it will require less calls for larger
operations in C space.

Here is an example from your web page:

Sending data is a sequence of commands to prepare a data-package
and one command to send this package.

// get the "send" object from the "msgque" object
struct MqSendS * const send = msgque->send;
// init the data-package
MqSendSTART (send);
// fill the data-package with data
MqSendI (send, myInteger);
MqSendC (send, "myString");
// send the data-package to the server
MqSendEND (send, "IDNT", NULL);

A first thought would be a class "Connection" and a method "send_package" that
takes an arbitrary number of positional arguments, such as

connection = some_source.connect()
connection.send_package(my_int, "myString", end_id="IDNT")

In case you do not know the required data type packing (which is explicit in the
C example), you can either wrap the types in some kind of typing construct
(which might degrade performance, unless you know that you do not need it in
most cases), or define message packing formats in advance in some way, e.g.
similar to Python's "array" module.

Just an idea. Since you appear to be the main author of that library, I assume
that you know best how to make it usable.

Stefan
 
A

Andreas Otto

Stefan said:
Andreas said:
I'm writing a native language binding for a library.

http://libmsgque.sourceforge.net/

Every native method called by PYTHON have to return
a PyObject* even if the function itself does not
return anything.
[...]
Question: what is the best return statement for a "void" function ?

Hmmm, this sounds like your goal is to write an exact 1:1 wrapper of the C
library API (for which there are tools like SWIG&friends). If the library
happens to have a rather unusual, close-to object oriented, high-level C
API, that might work. Otherwise, you might want to try to wrap it in a
more Pythonic look&feel style, that wraps operations and use-cases rather
than plain functions. That should make it easier to hide things like
memory allocation and other C implementation details from users, and will
generally increase the performance of your binding, as it will require
less calls for larger operations in C space.

Stefan

Thanks for your help ..

I'm almost finished ... it took me ~1week from a non Python developer to:
1. download, install python
2. learn how to use python, syntax, class, objects, protocol, ...
3. learn how to use the native interface, ~hundreds of C functions
4. finally create a project add my native code, compile, build ... test
-> I just add one extra type I call them "PyMqS_type"

all the special tools are not necessary because
if you wrote one language interface you can write every language interface
-> the tasks are allways the same... just the language-specific-names
are changing


mfg

Andreas Otto
 
A

Andreas Otto

Propable you can help me with an other problem ...

the following code crash with:

==31431== Process terminating with default action of signal 11 (SIGSEGV)
==31431== General Protection Fault
==31431== at 0x4EA5151: PyObject_GenericGetAttr (object.c:982)
==31431== by 0x4EF1FBD: PyEval_EvalFrameEx (ceval.c:1941)
==31431== by 0x4EF5261: PyEval_EvalCodeEx (ceval.c:2869)
==31431== by 0x4E91618: function_call (funcobject.c:628)
==31431== by 0x4E6C7AC: PyObject_Call (abstract.c:2161)
==31431== by 0x4E8055A: method_call (classobject.c:323)
==31431== by 0x4E6C7AC: PyObject_Call (abstract.c:2161)
==31431== by 0x4E6DFFE: PyObject_CallFunctionObjArgs (abstract.c:2392)
==31431== by 0x6B8A43B: Python_pymsgque_pCallVoidMethod (pymisc.c:36)
==31431== by 0x6B8991D: PythonChildCreate (pymsgque.c:89)
==31431== by 0x6D9E15F: pTokenCheckSystem (token.c:547)
==31431== by 0x6DA5110: pReadHDR (read.c:385)

with the following scenario

1. I have an object on an class
2. this object has a callable method context->config
3. I create an additional object of the same class
4. now I want to bind the context->config to the new object
5. I use:
context->config = PyMethod_New(PyMethod_GET_FUNCTION(context->config),
(PyObject*)context->self);
6. but call this object with "PyObject_CallFunctionObjArgs" create a crash

this is my C code with some helper

if (context->self == NULL) {
context->self = PyObject_New(PyMqS_Obj,(PyTypeObject*)context->class);
M0
printO(PyMethod_Function(context->config))
if (context->config != NULL)
context->config = PyMethod_New(PyMethod_GET_FUNCTION(context->config),
(PyObject*)context->self);
M1
if (context->create != NULL)
context->create = PyMethod_New(PyMethod_GET_FUNCTION(context->create),
(PyObject*)context->self);
M2
printO(context->config)
printO(PyObject_Type(context->config))
}

// 4. set the 'hdl'
context->self->msgque = msgque;

// 5. init the new object
M3
if (msgque->config.server == MQ_YES && context->config != NULL) {
switch (NS(pCallVoidMethod)(msgque, context->config, NULL)) {
case MQ_OK: break;
case MQ_CONTINUE:
case MQ_ERROR: goto error;
}
}
M4

this is the output:

output from the first object without error:
configO -> <bound method Server.config of <__main__.Server object at
0x2acee8eb7830>>
PyObject_Type(configO) -> <class 'method'>
PythonChildCreate(pymsgque.c:87) -> 33333333333333333
PythonChildCreate(pymsgque.c:95) -> 44444444444444444

output from the second object with the crash:
PythonChildCreate(pymsgque.c:71) -> 00000000000000000
PyMethod_Function(context->config) -> <function config at 0x2acee8ead8d0>
PythonChildCreate(pymsgque.c:75) -> 11111111111111111
PythonChildCreate(pymsgque.c:78) -> 22222222222222222
context->config -> <bound method Server.config of <__main__.Server object at
0x2acee8a67b20>>
PyObject_Type(context->config) -> <class 'method'>
PythonChildCreate(pymsgque.c:87) -> 33333333333333333
 
S

Stefan Behnel

Andreas said:
if you wrote one language interface you can write every language interface

This is like saying: if you used one programming language, you can use every
programming language. "Use" is different from "master" or "appreciate".
-> the tasks are allways the same... just the language-specific-names
are changing

That's the typical SWIG problem: you can generate wrappers for tons of
languages, mostly automatically. But none of them will feel 'native' to the
users of each of the target languages (well, possibly excluding C and Java here).

As the author, you write a wrapper once (and maybe keep maintaining it), but
every user of the wrapper will have to get along with its API that was copied
into his/her language from another one. And there are usually a lot more users
than authors.

I'm not undervaluing your work. It's good to have many, many library bindings
for Python. But having a "good" one would be even nicer.

Stefan
 
T

Terry Reedy

Andreas said:
Hi,

I'm writing a native language binding for a library.

http://libmsgque.sourceforge.net/

Every native method called by PYTHON have to return
a PyObject* even if the function itself does not
return anything.

I have 2 possibilities for return a PyObject*


1. the first argument of the method function
-> return self;
2. an entire new empty object
-> return Py_BuildValue("");

Question: what is the best return statement for a "void" function ?

P.S: NULL is not allowed, because NULL is returned in the case
of an "error"

To provide a Pythonic interface, error returns should often be converted
to Python exceptions.
 
T

Tim Rowe

2009/4/20 Stefan Behnel said:
That's the typical SWIG problem: you can generate wrappers for tons of
languages, mostly automatically. But none of them will feel 'native' to the
users of each of the target languages (well, possibly excluding C and Java here).

On the other hand, a thin wrapper around a library will let the user
leverage existing library documentation, so the choice is not a
complete no-brainer.

One approach (used in the Ada community for it's MS Windows bindings,
for instance) is to have a thin wrapper and build the thick wrappers
on top of that. Most Ada MS Windows thick wrappers (ie, ones that feel
natural to Ada) are built on top of Win32Ada, which stays as close to
the underlying C interface as it can.
 

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,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top