On Wednesday 25 May 2011 16:22:34 John Cummings wrote:
> >> I understand the need and semantics for changing the handling of arrays
> >> for function arguments. However, I am not trying to change the behavior
> >> for a function argument in this case. I am trying to access a member (or
> >> class static) variable that happens to be an array. The example I gave
> >> is roughly as follows:
> >> 
> >> class Foo
> >> {
> >> 
> >> public:
> >>     // constructor, other methods, etc.
> >>     size_t scalar;
> >>     size_t array[2];
> >> 
> >> }
> >> 
> >> As you suggested, adding a primitive-type tag like this:
> >> 
> >> <primitive-type name="size_t" default-constructor="0"
> >> target-lang-api-name="PyLong" />
> >> 
> >> 
> >> works great for the member variable "scalar" above. It does not handle
> >> the member variable "array" above. It really can just become either a
> >> Python tuple or a list, with a slight preference for a tuple in the case
> >> of a static const class variable that happens to be an array.
> >> 
> >> Have I missed something?
> > 
> > Oh, sorry now I see, it's a public attribute of your class, you are right
> > there's no special semantics in this case, is clear what should be
> > exported to Python.
> 
> Well, that's too bad. I was hoping I missed something obvious (not
> really because that would mean I asked a redundant question).
> 
> > But there are some problems...
> > 
> > We can't export if as a tuple because tuples are immutable objects in
> > Python, so we need to export this attribute as a list, however we need
> > to forbidden
> 
> > the user to do some constructs like:
> As I noted, in the actual library I am writing bindings for, the
> variable is a constant static class variable, so the immutable nature of
> a tuple would be perfect for that application. In other words, for a C++
> class like this:
> 
> class FooStatic
> {
> public:
>     static const size_t array[2];
> }
> 
> I believe a tuple of size 2 would be a logical mapping between the two.
> However, that is not how I posed the problem to the mailing list.
> 
> > foo = Foo()
> > foo.array.append(2);
> > 
> > Because the size of array must be constant.
> 
> Good point.
> 
> > There is another problem regarding to the sync between Python and C++, if
> > the user do:
> > 
> > foo.array[0] = 3
> > 
> > The array gets modified by him, ok, but how C++ will knows that the list
> > was modified? C++ need to knows it to proper copy the values back to the
> > C++ Foo instance that lies behind the Pyhton object.
> 
> Well, knowledge of the modification to the values in the array is also a
> problem in C++ unless I am mistaken. I would think that if tracking the
> changes was desirable, one would use a more sophisticated class than a
> plain array of size_t values. Your next paragraph tells me that perhaps
> I do not yet fully grasp what you are talking about.
> 
> > The problem is that the Python list is another thing, different from the
> > C++ array and we can't tell the Python list to point to the C++ address
> > of Foo.array, so we need to copy some data to Python but we never know
> > when to copy this values back to C++.
> > 
> > However I think all these problems could be addressed if we create a new
> > object to deal with this, this object would hold a pointer to the C++
> > array it's mapping and direct change it when necessary, but this rises a
> > new set of minor problems, e.g. we would need different objects for
> > different C++ types, etc..
> 
> That sounds like a template class just waiting to happen to me. If you
> can point me in the right direction, I can take a swing at it, although
> I'll warn you that I am CPython novice at best.

Ok, I'll try to re-phrase my explanation:

Every change you do in a Python object should reflect in the underlying C++ 
object binded by this Python object, so if you call:

foo = Foo()
foo.scalar = 3

Python will call the setter of Foo that will write the value (3) in the scalar 
attribute of a C++ instance of the Foo class hidden in the PyObject 
represented by the foo variable, in *pseudo CPython code* the setter function 
will do something like  this:

void FooScalarSetter(PyObject* self, PyObject* value)
{
    Foo* cppSelf = (Foo*) Shiboken::getCppPointer(self);
    cppSelf->scalar = PyInt_AsLong(value);
}

In the real life we need to check a lot of other things but the basics are 
there, so due to what the setter function do we are sure that after the 
execution of the Python line of code "foo.scalar = 3" the underlying C++ 
object will have the value 3 stored in the scalar attribute too. The same 
isn't possible when scalar is a list and do user modifies it, e.g.

foo.array[0] = 3

This will call the Foo getter for the attribute "array", a list is returned 
with all values copied from the ones found in the underlying C++ instance of 
Foo and after this the binding has no control about what the user will do with 
the list, it's the same as:

a = foo.array # now there's no relation between "a" and "foo"
a[0] = 3 # nothing happens to "foo"

This is why I told that is necessary do create a new Python object to deal 
with this problem, so instead of returning a Python list from the getter we 
would return a special object that knows that this collection is somehow 
linked to another object and updates it correctly, maybe C++ templates would 
do part of the job of copying the values back from Python to C++, I don't know 
yet... just random thoughts at the moment =]
 
> Thanks
> John Cummings

-- 
Hugo Parente Lima
INdT - Instituto Nokia de Tecnologia

Attachment: signature.asc
Description: This is a digitally signed message part.

_______________________________________________
PySide mailing list
[email protected]
http://lists.pyside.org/listinfo/pyside

Reply via email to