[C++-sig] Patches and complete pyste replacement prototype for pyplusplus

Matthias Baas baas at ira.uka.de
Fri Feb 24 19:20:56 CET 2006


Allen Bierbaum wrote:
> Roman and Matthias:  I have attempted to implement some solution or
> method for every topic we have talked about so far on the e-mail list.
>  If there was anything I missed please let me know.  This API has
> evolved from my original proposal and thus differs in implementation
> from the interface Matthais has proposed.  I read his proposal though
> and tried to incorporate the ideas where possible.  If I haven't used
> an idea it is either because I found another way to handle the issue
> or I found issues with either the use of implementation.

Well, as I have already seen your first version and even used that as a 
basis for my own version, it shouldn't come as a surprise that I 
actually do prefer some things as they are implemented in my proposal 
(otherwise I wouldn't have changed them in the first place). ;)

But first, I'd like to note that the overall principle of our two 
versions is actually the same and because of some minor details it just 
appears to be different.
Allen has a class called "Module" that is used to control the internals 
of pyplusplus. In my version, this class is called "Pipeline" (as in my 
opinion, this class actually represents the pyplusplus "core" I find the 
name "Module" a bit misleading. But some might say this is nitpicking... ;)
In Allen's version, the user always explicitly creates an instance of 
that class himself, in my version this instance is created internally 
and each method is also available as function which internally calls the 
corresponding method of the global instance (if desired the user could 
also create an instance himself).
In Allen's version there are three main "control methods": parse(), 
createCreators(), createModule(). In my version, I have the three 
methods parse(), codeCreators() and writeFiles() which serve the same 
purpose (as said above, these methods are also available as functions).
In both versions, the second step (creating the code creators) is done 
internally if it wasn't done explicitly by the user (in my version I 
also applied that rule for the parse() step, but I admit that probably 
everyone has to do that step manually anyway (but it's a nice feature 
for a "Hello World" example :) ).
In both versions, there are methods Class, Method, Function, etc. to 
select one or more particular declarations that can then be decorated to 
customize the final bindings. In Allen's version, these function either 
return a DeclWrapper or MultiDeclWrapper object (depending on whether 
the selection contains one or more declarations). In my version, the 
return value is an IDecl object (that always acts like a MultiDeclWrapper).
Decorating the declarations also looks almost the same in both versions.

So far, both versions are almost identical. However, at the moment, a 
big difference is the expressiveness of the declaration selection 
methods (Class, Method, Function,...) and the exact semantics of the 
declaration wrappers. And here I actually prefer my version where 
obtaining an IDecl object is like doing a database query to retrieve a 
set of declarations that meet certain requirements. The resulting IDecl 
object can reference an arbitrary number of declarations scattered all 
over the declaration tree. It can even be empty and still provide the 
decoration interface. Such a "database query" can be further refined by 
calling the Class, Method, Function,... methods again on a IDecl object 
(this is a feature that the MultiDeclWrapper in Allen's version 
currently does not allow). Each individual query can also be composed of 
several filters where different filter types are concatenated with AND 
and filters of the same type are concatenated with OR (see 
http://i31www.ira.uka.de/~baas/pypp/classpyppapi_1_1decl_1_1_i_decl.html#063f1880bb6bc164d2f0ecd5fc92a3c1).
In Allen's version, all queries are based on the declaration type and 
name. Queries for methods can optionally use the arguments or return 
type as well (but the name is still mandatory). As this is a subset of 
the query filters in my version I think it wouldn't be a problem to 
elevate Allen's version to the same expressiveness as my version.

I tried to convert my current project to Allen's API but as I have used 
my "multiple selection" feature quite often I didn't translate all of 
it. Here are some examples:

In my version I'm ignoring all protected methods of all classes like this:

Method(accesstype=PROTECTED).ignore()

Here, I don't know what the corresponding code would look like in 
Allen's version (but I suppose that it would also be the Method() query 
that would provide a similar argument, right? But this shows already 
that the 'name' argument shouldn't be mandatory).

Then I ignore all ()-operators that return a reference to a float or 
double by the following line:

Method("operator()", retval=["float &", "double &"]).ignore()

Again, this addresses several classes and several methods at once. There 
are four filters (and three filter types) involved in this query:

- A "type" filter because I was using the Method() function 
(alternatively I could have used the generic Decl() function together 
with the type=METHOD filter (which is what happens internally))
- A "name" filter (in my API I'm using the convention that the first 
argument is guaranteed to be the 'name' filter. All other filters must 
be specified by keyword arguments)
- Two "return value" filters (which are concatenated with OR)

When I translated my project to Allen's API the above line became:

for cls in classes:
     Cls = mod.Class(cls)
     try:
         op = Cls.Method("operator\(\)", retval="float &|double &")
         op.ignore()
     except RuntimeError:
         pass

(classes is a list of class names that should be exposed. I have that 
list anyway, so it was no problem to use that one here)
I had to check for the RuntimeError exception because the Method() query 
could be empty which is actually ok in my case. This is an example that 
shows that it can be ok that a query produces an empty result.
Another thing that was confusing is that the name is *always* treated as 
a regular expression. In my first attempt, I was just searching for 
"operator()" and didn't get the expected results. After looking at the 
API code I noticed that the string is treated as a regular expression 
which means the brackets already have a special meaning and have to be 
escaped. This is the reason why I suggested to mark regular expressions 
explicitly (in my version by enclosing it between two '/' (maybe this 
should be another character as the slash could actually be part of a 
path name)).

I have more such examples, but I think they won't highlight any further 
issues, so I'll leave them out.

I can't comment on the features where Allen is clearly ahead of my 
version (such as templates) as I was focusing on the stuff that I need 
for wrapping my SDK (which doesn't have any templates).


- Matthias -




More information about the Cplusplus-sig mailing list