Re: C++ to Python and returning members of a C++ object

Terry Barnaby <[email protected]>
Newsgroups gmane.comp.programming.swig
Message-ID <[email protected]>
Hi Jake,

Thanks for the information. That is one complex typemap syntax !
Is there any information on how this works and how to use it ?
I will have a try using it to implement a reference count system on all 
references to members returned from all C++ objects.

Terry
On 04/08/2020 22:35, Jake wrote:
> I don't believe anyone has said it would not be useful.  There are 
> just some questions about implementation.
>
> Since the Python container patch is in SWIG already and includes 
> machinery to set a back-reference (it effectively does the equivalent 
> of `child.__owner = parent` in Python), and this also accomplishes 
> automatic reference/dereference, why not re-use it rather than 
> re-implement in a different way?  It also does not require modifying 
> the native-code part of SWIG; much of SWIG's language support is 
> written in SWIG's language.
>
> Typemaps can be a little tricky to place sometimes but can be pretty 
> generic.  You seem to think you'd have to repeat them for all your 
> types, but this isn't really the case, e.g. my container patch sticks 
> one in:
>
>     %typemap(ret, fragment="reference_container_owner", noblock=1) 
> value_type& {
> (void)swig::container_owner<swig::traits<$*1_ltype>::category>::reference($result, 
> $self);
>     }
>
> This applies to all the container functions returning a reference to 
> the value type.  There is even a placeholder type `SWIGTYPE` you could 
> use, so something like
>
> %typemap(out) SWIGTYPE&
>
> Would apply to everything returned by reference, it does not need to 
> be repeated type-by-type.  However, it does give the user the option 
> of overriding the behavior by specifying their own typemap at the same 
> or a more specific level.
>
> The other thing the container patch has that could be re-used is that 
> template specialization on the type traits, which lets you distinguish 
> things which are wrapped as pointers vs values.  This is to prevent 
> setting a back-reference to something that got copied like an int, 
> less overhead and you don't pin the parent memory unnecessarily.
>
> William probably has some other subtleties in mind on when it should 
> apply or not.
> -Jake
>
> On Tue, Jul 28, 2020 at 1:44 AM Terry Barnaby <[email protected] 
> <mailto:[email protected]>> wrote:
>
>     Hi William,
>
>     As stated previously I have some reasonably large object
>     orientated C++ class libraries where classes/structs make use of
>     class members extensively and at depth. To have to add special
>     typemap for all of the cases where member objects are returned in
>     all situations would end up with a lot of work, a lot of SWIG code
>     to handle all the possible cases, would be difficult to test and,
>     I think,  unmaintainable.
>
>     I assume your idea with a typemap memberout would end up being
>     similar in that I would have to add a memberout typemap for every
>     class/struct type in the library ?
>
>     If so I would have thought this memberout code would end up having
>     to increment the reference on the container object and having some
>     code that decrements the reference on the container object when
>     the returned member is deleted similar to my simpler proposed method.
>
>     From my perspective, the ideal for SWIG, would be to wrap these
>     libraries with the absolute minimum of SWIG code with it just
>     using the C++ headers. I nearly have this apart from the returning
>     of dangling pointers, handling C fixed arrays (which I think SWIG
>     could also automatically do) and adding Python list methods to
>     simplify the use of the C++ lists in Python.
>
>     It seems to me that the current implementation (C++ -> Python),
>     where a member of a C++ object is returned by reference without
>     incrementing the reference on the container object is
>     fundamentally flawed. It quickly leads to dangling memory pointers
>     and segment faults that are horrible for a user to track down and
>     the fix of telling the user to create a copy of each C++ member
>     object they want to return from a Python function is also not good.
>
>     I thought my simple idea of just incrementing the reference of the
>     containing object whenever a pointer to its internal data is
>     returned for use and then decrementing this reference when the
>     returned member goes out of scope was the simplest, easiest and
>     most tidy way of achieving this with no SWIG code (apart from
>     turning the feature on at the top of the SWIG code file). It is
>     only a few lines of code added to SWIG and it should work in all
>     reference memberout cases and all depths automatically with very
>     little overhead. This would likely work for the std:vector and all
>     other such cases automatically. As far as I can see the only
>     detractor is the delayed container object destruction that could
>     affect some code, but I would have thought that would not affect
>     many cases and in these the feature could be turned off for the
>     particular classes or the user asked to make a copy of the
>     returned member.
>
>     Now I may be missing something fundamental in this, but if not
>     (and no one so far has stated why this won't work), why don't you
>     think this would be a useful feature in SWIG ?
>
>     Terry
>     On 27/07/2020 22:30, William S Fulton wrote:
>>     Hi Terry
>>
>>     I don't know why you have not based your solutions on the
>>     approaches mentioned in my original response. One of those is the
>>     std::vector solution that Jake also brought up. What I think
>>     might work is, instead of a new feature, is a new typemap that is
>>     only used when wrapping 'getter' member variables. Let's call it
>>     say memberout. It will contain the typemap code that I posted
>>     originally and only be generated when wrapping member variable
>>     getters. I'd need to think how to make it work only when needed,
>>     which I think is for all member types stored by value that are a
>>     SWIG wrapped proxy class type.
>>
>>     William
>>
>>     On Wed, 22 Jul 2020 at 13:45, Terry Barnaby <[email protected]
>>     <mailto:[email protected]>> wrote:
>>
>>         In effect, this is what my experimental patch does at the
>>         SWIG C++ wrapping level. It adds a PyObject* to the members
>>         SwigPyObject that is set to point to the container object
>>         that the members SwigPyObject is referencing. This PyObject*
>>         pointer is set on a members SwigPyObject object when a
>>         pointer/reference to a member is created as well as the
>>         container object having its reference counter incremented.
>>         When the members SwigPyObject is deleted it will use the
>>         PyObject* to decrement the container objects reference
>>         counter if the PyObject* is actually set. There is the
>>         addition of the pointer to every SwigPyObject and the call to
>>         the reference counter increment/decrement but that is all so
>>         it seems pretty efficient if this method is ok.
>>
>>         It is simple, but I am unsure of its implications in the
>>         wider SWIG codebase as I don't have much knowledge of this.
>>         So any comments on this approach welcome.
>>         If ok, I will have to work out how to use the "feature"
>>         functionality of SWIG to implement it properly.
>>
>>         Terry
>>
>>         On 22/07/2020 13:00, Jake wrote:
>>>         I support this idea too.  I had a PR that got into 4.0 for
>>>         essentially the same issue on containers like std::vector
>>>         that might be of interest:
>>>
>>>         https://github.com/swig/swig/pull/1234
>>>
>>>         Strategy there was to point to the parent wrapper from the
>>>         child wrapper to tie their GC lifetimes together.
>>>
>>>         -Jake
>>>
>>>         On Wed, Jul 22, 2020, 7:42 AM Terry Barnaby
>>>         <[email protected] <mailto:[email protected]>> wrote:
>>>
>>>             Hi,
>>>
>>>             Yes, it is a very simple patch that just increments the
>>>             reference counter on the SWIG wrapped C++ object when a
>>>             member of it is returned via a pointer/reference and
>>>             decrements that reference when the returned member is
>>>             finally deleted. The idea would be to implement this as
>>>             a SWIG feature than could be turned on for an individual
>>>             class/struct or the whole library. I believe it would be
>>>             of use if quite a few cases, but as said, I may be
>>>             missing something.
>>>
>>>             Terry
>>>             On 22/07/2020 10:57, D Haley wrote:
>>>>
>>>>             Dear List,
>>>>
>>>>             I would like to support the demand side of things for
>>>>             this, I maintain a small library that provide
>>>>             C++->python using swig, and we've had troubles with
>>>>             library users having memory corruption when using
>>>>             python. Our workaround has been to discourage the
>>>>             inadvertent creation of temporary variables, but it
>>>>             seems a poor solution.
>>>>
>>>>             As a library maintainer, it sounds like (and I've not
>>>>             gone through the patch in detail), that this reference
>>>>             counting approach would help minimise the chance of
>>>>             corruption by early collection?
>>>>
>>>>             Thanks.
>>>>

_______________________________________________
Swig-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/swig-user
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.