[C++-sig] Re: Auto-Generation and BPL v2

David Abrahams dave at boost-consulting.com
Wed Nov 6 19:58:46 CET 2002


Brad King <brad.king at kitware.com> writes:

> Dave,
> 
> > > 1.) Namespaces v. Python Modules
> > >
> > > All code in ITK is in a C++ "itk" namespace.  We'd like to have this
> > > namespace reflected in the python wrappers with code like this:
> > >
> > > # Load the ITK ptyhon wrappers.
> > > import itk
> > >
> > > # Create an instance of an ITK object.
> > > # Equivalent C++ code:
> > > #   itk::Object::Pointer o = itk::Object::New()
> > > o = itk.Object.New()
> >
> > What's the problem? Maybe it's the fact that we don't have static
> > function support in Boost.Python yet?
> 
> Oops, I didn't finish this section of the email.  I meant to point out
> that I don't see a way to have nested namespaces treated as modules in
> Python through BPL:
> 
> # itk::foo::Bar()
> itk.foo.Bar()

Sure there is. See 

  http://www.boost.org/libs/python/doc/v2/scope.html

and this thread, including Ralf's followup:

   http://aspn.activestate.com/ASPN/Mail/Message/1411775

> Even if it were not possible to separately load this "itk.foo" module, it
> would still be nice from a naming perspective.

If you do it as a subpackage, it is possible to separately load it.

> > I understand why you want this, but for this /particular/ case I'd
> > suggest that an interface like
> >
> >         o = itk.Object()
> >
> > would be more appropriate. Why expose to users that there's a factory
> > function at work here?
> 
> I agree that this particular case is prettier when hiding the New()
> method, but there is also something to be said for a one-to-one
> correspondence among C++, Tcl, and Python implementations of the
> same program.

Yes.

> Also, CABLE is intended to be a tool separate from ITK, and should not
> have ITK-specific hacks in it.  Then, in order to achieve this syntactic
> change there would have to be a way of specifying it in the configuration
> file.  One of my design goals for CABLE was to produce wrappers that
> reflect the original C++ as closely as possible, and with as few
> configuration options as possible.

OK, it sounds like you'll need static method
support... eventually. Though it looks like you just want submodule
support from reading your earlier text.

> This actually brings up the other main issue with automatic
> generation.  Whenever a return_value_policy is required, CABLE will
> have to make some assumptions, and probably just always use
> reference_existing_object.  

  :(

I hate the idea that you can crash things from Python.

> Anything different would require per-method configuration, which
> already starts to defeat the purpose of auto-generation of wrappers.

Yes.

> > If you must have the static function interface, we just need to have a
> > discussion of the C++ interface questions I pose in the link above, so
> > that I can come up with a good design.
> 
> I'd definately prefer the def(..., static_()) approach over having
> static_def.  Here is another approach that crossed my mind:

Actually, I was not proposing that. I was proposing:

        def(..., static_  )
                        ^^

> struct A { static void StaticMethod(); };
> 
> class_<A>("A", init<>())
>   .def("StaticMethod", static_(&A::StaticMethod));

I thought of that, too.

> I'm not sure I'd prefer this over
> 
> class_<A>("A", init<>())
>   .def("StaticMethod", &A::StaticMethod, static_());
> 
> but I thought I'd mention it anyway.

Given the two options with parens, I definitely prefer the first one.
And  I think I prefer it overall, since it nicely associates
staticness with the function to be wrapped.

> > Aha. I've considered doing something like this in the past, but I
> > thought that tracking every object in this way *by default* would be a
> > price that not all users would be willing to pay.
> 
> In Tcl the tracking is more necessary because the wrapper objects
> each have a corresponding Tcl command used to invoke methods on that
> object.  CABLE needs to keep track of all the commands it creates
> and destroys to keep this working.  The tracking isn't as necessary
> for Python, though, so you're right that the extra cost may not be
> worth it.

It's not clear to me yet what the best approach is. As I said before,
I kind of hate the idea of generating automatic wrappers which can
crash the system. I think if all C++ objects are intrusively-counted,
it's not a big deal to avoid this problem, though.

> > There are also issues of base/derived class tracking (what happens if
> > you're tracking the base object and someone returns a pointer to the
> > derived object, which has a different address?) which make doing it
> > right especially difficult.
> 
> I went through the same thought process for CABLE's Tcl wrappers.
> At the time I decided to go for the pointer comparison and ignore
> the problems to get something working.  I have yet to thoroughly
> revisit the issue.  However, I've toyed with the idea of automatic
> down-casting of pointers to polymorphic C++ types.

There is already some facility for that in Boost.Python. Take a look
at libs/python/src/object/inheritance.cpp if you care. However, you
have to register all the participating classes for this to work.

> > However, if itk's smart pointers are indeed intrusive, it seems to
> > me that you can just generate thin wrappers for your
> > raw-pointer-returning functions which generate the smart pointer
> > for you.  > [snip] Another approach we could consider is to
> > arrange a way for you to say, "pointers to any classes derived
> > from X should be converted to python this way". That requires an
> > investment in some more Boost.Python work, so it might have to
> > wait a little while...
> 
> These options are definately worth my consideration, but this decision
> will depend somewhat on the configurability decision I mentioned above.

Which one?

-- 
                    David Abrahams
dave at boost-consulting.com * http://www.boost-consulting.com





More information about the Cplusplus-sig mailing list