[C++-sig] pyplusplus ui / API

Allen Bierbaum abierbaum at gmail.com
Tue Feb 14 15:51:42 CET 2006


I can give my comments relative to your questions and how they relate
to the proposed interface in
http://mail.python.org/pipermail/c++-sig/2006-February/010222.html.


On 2/14/06, Roman Yakovenko <roman.yakovenko at gmail.com> wrote:
> Hi. Here is my thoughts about next messages:
> http://mail.python.org/pipermail/c++-sig/2006-February/010213.html
> http://mail.python.org/pipermail/c++-sig/2006-February/010222.html.
>
> First of all what is user domain specific language (DSL)? Matthias
> Baas provided the answer:
>
> >My suggestion would be to make the declaration tree
> >more "feature rich" and make it the main data structure that the user
> >will interact with.
>
> And I think he is right. Here is the "language"( public interface ) of pygccxml:
>     calldef
>             args
>         member_function
>         constructor
>         destructor
>         member_operator
>         casting_operator
>         free_function
>         free_operator
>     class_declaration
>     class
>         bases
>         derived
>         public_members
>         protected_members
>         private_members
>     enumeration
>     namespace
>     typedef
>     variable.

Agreed.  The pygccxml tree provides a very good hierarchical structure
by which we can look at the code to wrap and modify it as needed.

> So basically, if you do not want to export some declaration, you write
> decl.ignore = True. By default for all declarations from std namespace
> and built-in ones
> ignore equal to True. This will solve famous, :-(, filtering problem.

In the interface I wrote I actually reversed this logic a little.  I
found it easier to think of adding a flag _expose_flag and setting
that flag false for all declarations by default.  This way the user
needs to explicitly say what they want exported.  In general I think
explicit is more clear then implicit so I think this works out well.

> Also, it will not solve
> filtering "spaghetti code". I just don't see how it can do it. If you
> have a lot of special cases
> you have to write them all somewhere. Take a look on the example from the second
> message.

The interface does actually help with this quite a bit.  My example
was a little complex since I was testing quite a few features, but
still the only things you need to write are the explicit
classes/methods/namespaces you want to expose.  Even this can be
simplified quite a bit because of the recursive and regex support
provided.

For example if you just wanted to export an entire namespace you could write:

mod.Namespace("my_namespace").expose()

or if you want to expose all classes you could write:

mod.Class(".*").expose()

For many simple cases this is the only code you would need for
specifying everything you end up exporting.

At least to me this is quite an improvement over the "spaghetti code"
filter because it is very direct and clear what is being exposed.

>
> Open question: If user set ignore to True on namespace and\or class
> does it mean that
> pyplusplus should not export whole namespace\class?

The way I solved this was to make expose recursive by default so when
they expose a namespace it will expose everything in that namespace. 
If they want to be more selective then they need to set the argument
to expose() to False to prevent recursion.  So in effect I avoided
making a decision on this one and let the user decide for themselves.

> Second thought is to "hide" a little pygccxml. This will allow simple
> cases to be really simple:
> module = create_module( files, GCC XML configuration )
> #by default all declarations outside of the files ignore property will
> be set to True ???
> module.name = "hello_world"
> module.write('hello_world.cpp') #if name has not been set exception
> will be thrown
> or
> module.write_files('.') #split code of module to multiple files

I attempted a start to this.  My goal was to encapsulate as many
internal details as possible and to try to make the interface straight
forward for simple things while still allowing power users to
customize.  It works fairly well so far but there are a few things
that still need added:  caching support, (un)defines, mulit-file, and
multi-module.

> Class module_t will contain declarations_tree property. User will be
> able to travel
> the tree and:
>     to set ignore flag to True or False ( no more confusion )
>     to set call policies ( no more call policies factory )
>     to set alias
>     to set documentation string
> and may be few other things, right now I don't have good definition
> for "other things"
>
> Class module also will contain few "get\find\constructor" helper functions.
> Basically they will search for some declaration according to some criteria.
> This is exactly what Matthias Baas proposed and Allen Bierbaum did.
>
> So far so good. Until now we almost back to usability level of Pyste.
>
> Now questions I can not answer:
>
> 0. Does DSL should be based on C++ or Python terminology?
>     For example: Matthias Baas and Allen Bierbaum talk about member
> and free functions
>     as method.
>
>     I think that we should peek C++\Boost.Python terminology? There is
> no (good ?) way
>     to express register_to_python_ptr or implicit_convertible using
> Python terminology.

I would like it based on C++ terminology.  Any place that my example
is not was an oversight by me and should be refined.

I would like to express register_to_python_ptr and
implicitly_convertible as something like:

base_c = exmod.Class("Base")
base_c.use_shared_ptr()
base_c.hold_with_shared_ptr()
base_c.hold_with_ptr(ptr_type)

There would still need to be a way to add custom
implicitly_convertibles but I don't yet see how to get those into the
decl tree (see below).

>
> 1. What about code creators? Code creators is very powerful concept.
>     1.1 What is the user interface to inject code "X" under class "Y" ?
>     1.2 How user can customize generated code. For example recent
> registration order
>           problem. The quick and dirty work around was to set
> use_keywords property of
>           function_t code creator to False.
>     1.3 For some declaration pyplusplus creates more then one code creator:
>           1.3.1 class has 2 relevant code creators: class_t and wrapper_t
>           1.3.2 if class has "casting constructor /* struct X{ X(int); }; */
>                   or casting operator then implicitly_convertible code
> creator will be created.
>           1.3.3 There are also code creators that creates
> register_ptr_to_python code
>
>     I think you've got the idea. My point is that user should be able
> to work with code
>     creators tree.
>
>     I do have some idea how to implement this, but first I would like
> to know what do you
>     think?

This is an area where I am at a lose as to how to handle this.  If we
are "filtering" and making decisions based on the decl tree it seems
like the cleanest interface to the user would be to allow them to make
some of these customizations in that gccxml tree.  Unfortunately this
tree does not have the code generators yet since it is really used to
create the code generators.

One idea I did have is that we graft on new nodes to the decl tree
that are custom to pyplusplus without extending gccxml.  For example
we could add a custom_code_t derived from declarations_t that could be
added into the declaration tree by the user to add code anywhere. 
Similarly there could be a new node for implicitly_convertibles and so
on.  The main reason for doing this would be to allow the user to
write code like:

test_ns = exmod.Namespace("test")
test_ns.addImplictConvertible("testPtr1", "testPtr2")
test_ns.addHeader("/usr/local/custom_include.h")
test_ns.addCode("""
/* custom code. */
""")

Is it possible for the code creators to read from something like this
and create the correct creators?  We would lose some power with an
interface like this though so I think it would be important to allow
direct access to the code creators after they have been instantiated.

>
> 2. Pyste is able to create code without generating main. It is
> possible to do it with
>     pyplusplus, but you have to know low level details. How do you
> solves this problem?

I thought about this quite a bit last night and I have an idea.  The
key is that we want a way to generate a partial binding for a module
using an explicit function name and can be called later from a main
generator.  So we want to be able to end up with files like:

---- main_binding.cpp ---
void export_classA_binding();
void export_classA_binding();

BOOST_PYTHON_MODULE(test)
{
   void export_classA_binding();
   void export_classA_binding();
}

--- export_classA_binding.cpp --
void export_classA_binding()
{
...
}

--- export_classB_binding.cpp --
void export_classC_binding()
{
...
}


I think this could be handled if there were a way to tell the
generator that it is only creating a partial binding and a way to
specify the name of the contained registration method.  Then a
corresponding creator for the "main" file could be given a list of the
registration method names.

So and example of some code using this method would look something
like this (using the test pypp_api.py I proposed).

------------------------------------
header = [ "ClassA.h", "ClassB.h", "ClassC.h"]
binding_methods = ["export_classA", "export_classB", "export_classC"]

for h,b in zip(header, binding_methods):
   mod = pp.Module()
   mod.parse(h)
   mod.Namespace("test").expose()
   mod.createPartialModule("test_mod", b + ".cpp", b)

Module.writeMainFile("main_binding.cpp", binding_methods)
-----------------------------------

This could be improved upon by autogenerating the method and file
names but you get the idea.

>
> 3. Technical problem: pygccxml is stand alone project. It is useful on
> its own. I don't want
>     to pollute it with code that is only useful for pyplusplus. I
> think that next solution will
>     work, but I don't like it:
>     pygccxml defines next class pygccxml.declaration.class_t
>
>     pyplusplus will create new class that derives from
> pygccxml.declaration.class_t class.
>     Lets say it will be pyplusplus.declaration_wrappers.class_t.
> pyplusplus will change
>     __class__ attribute of pygccxml.declaration.class_t instance to be
>     pyplusplus.declaration_wrappers.class_t. Thus user will have
> "original" declarations
>     tree, full functionality of pygccxml and easy way to find out what
> he can\should
>     change\set for specific declaration. What I don't like is the
> trick, that changes
>     __class__ attribute.
>
>     May be you have an other solution.

Why derive a new class.  It seems like you could get by with just
injecting the flags/attributes that are needed to specify what the
creators should create.  Am I missing something here?

-Allen


>
> By the way it is not very difficult to implement this. I suppose it
> will take +- 2 weeks
> 1 week to implement - core functionality already exists, 1 week to stabilize.
>
> Thoughts, comments and suggestions are welcome.
>
> Thanks.
>
> --
> Roman Yakovenko
> C++ Python language binding
> http://www.language-binding.net/
> _______________________________________________
> C++-sig mailing list
> C++-sig at python.org
> http://mail.python.org/mailman/listinfo/c++-sig
>



More information about the Cplusplus-sig mailing list