[C++-sig] Re: Exposing C++ objects to Python at runtime

David Abrahams dave at boost-consulting.com
Tue Nov 25 04:52:29 CET 2003

Raoul Gough <RaoulGough at yahoo.co.uk> writes:

> Jonathan Warrington <jon at shirwin.com> writes:
>> Ah, ok I think I see where the communication problem was now.
>> What I was wanting to do, was have it so that my other components
>> would only know of that scripting engine interface, and use that to
>> register themselves at runtime when they are created, and therefore if
>> my XYZ class changes all I have to do is recompile that.  Not have to
>> generate new Boost.Python registration code, and recompile that
>> wrapper.
>> So,
>> App Starts
>> App creates an instance of Scripting Engine
>> App creates an instance of class XYZ
>> App passes scripting engine to XYZ->Init()
>> XYZ registers what it wants to be scriptable as scriptable
> Well, I don't know how realistic this is. 

It can be done, and something which provides language-independent
wrapping syntax is surely worthwhile.  I don't know if it's worthwhile
to do it with runtime polymorphism in this way.

> IIUC, you want some kind of
> an abstract interface that allows you to add new functions, object
> types and methods to various scripting engines. In this way, your
> classes can expose themselves to any of the engines, while having
> compile-time dependencies only on the abstract interface.
> So consider the following:
>>>> //Script function takes an arg count, an arg array, and returns a
>>>> //value
>>>> typedef void (*SCRIPT_FUNCTION)( int, ScriptVal**, ScriptVal* );
>>>> struct SW_ScriptEngine{
>>>>	virtual void initialize() = 0;
>>>>	virtual void release() = 0;
>>>>	virtual ScriptVal* executeScript(String script) = 0;
>>>>	virtual bool registerFunction(String name, SCRIPT_FUNCTION
>>>> func, String moduleName) = 0;
> class my_class {
>   void function1(int);
>   int function2() const;
>   void register_self (SW_ScriptEngine *eng_ptr) {
>     eng_ptr->registerFunction (&function1);
>     eng_ptr->registerFunction (&function2);
>   }
> };
> Now the type of function1 is "void (my_class::*)(int)" and the type of
> function2 is "int (my_class::*)() const". How is registerFunction
> going to be able to deal with those member functions (and all possible
> others)? 

It's not that hard to imagine.  registerFunction just needs to
generate a scripting-language-independent wrapper around the member
function which provides the means to invoke it and a way to get the
arguments initialized... something like:

    struct function
        virtual ~function() {}
        virtual std::size_t arity() = 0;
        virtual std::type_info const& result_type() = 0;
        virtual std::type_info const* const* arg_types() = 0;
        virtual void invoke(
            void* const* args_storage, void* result_storage) = 0;

It's then the engine's job to line up the language specific converters
for the types of the arguments and result and build a wrapper around
*that*.  In fact, now that I write it down it looks to me as though
Boost.Python could be organized in roughly this way at little extra
cost.  Maybe in version 3... ;->

The biggest problem is that there are interfaces which really do
require you to touch language-specific components in order to bind
them well.

Dave Abrahams
Boost Consulting

More information about the Cplusplus-sig mailing list