Boost logo

Boost :

Subject: Re: [boost] Interest in Remote Procedure Call Library?
From: Matus Chochlik (chochlik_at_[hidden])
Date: 2010-02-08 05:55:12


On Sun, Feb 7, 2010 at 5:30 PM, Daniel Larimer <dlarimer_at_[hidden]> wrote:
> Mirror looks interesting and for some reason never showed up on my google searches!  After reading the documentation it was unclear to me how one would use the "mirrored" interface other than to query the text description of the interface component types/names.  For example, there was no abstract (virtual) way of invoking a method either using boost::any, void*, or serialized parameters.  Perhaps I missed it.   It also appears that Mirror requires C++0x which limits its application.

Sigh, the docs still leave a lot to be desired, but I'm working on it so
it hopefully gets better soon.

Anyway, there is a run-time layer nicknamed "Lagoon" which provides
a dynamic interface based on the compile-time meta-data registered
with Mirror, that allows you to iterate through the member variables/
base classes/constructors/*member functions*/various specifiers/etc.

the docs can be found here: http://tinyurl.com/yz6pdbv

there is a template function called reflected_class<Class>()
(docs: http://tinyurl.com/ylag2tq) that returns a polymorphic
interface (meta_class: http://tinyurl.com/ylepo6e) reflecting a Class.

*Currently* it lacks the ability to call a function dynamically, but there is
a compile-time facility which can invoke a constructor or basically any
(member) function with a custom parameter supplier, through a uniform
interface and allows to pass the parameters for the function call from
any external source, a GUI, a database, an XML file, etc.

Similar thing will be added to the run-time layer, once some minor
issues are resolved. This way it will be possible to use a polymorphic
interface to create instances or to call a member function and
to supply the arguments in an application defined way.

But, what I was suggesting is that you could use the compile-time
meta-data provided by Mirror to generate the meta-data you are currently
registering with the META_INTERFACE and METHOD macros
(I did not look at the definition of these macros but there is a good chance
that this is possible)

There is a set of meta-function templates which work with the
meta_class returned by BOOST_MIRRORED_CLASS(Class),
for example:
member_variables<MetaClass> (http://tinyurl.com/yfygtay),
member_functions<MetaClass> (http://tinyurl.com/yggfqhe),
base_classes<MetaClass> (http://tinyurl.com/ylyvzkd),
etc.
which return ranges of meta-objects describing the members,
base classes, etc.

by using the compile-time meta-programming utilities
(http://tinyurl.com/ygv2ash) you can traverse or transform
these ranges into (nearly ;-)) whatever form you need.

>
> With respect to exceptions, that is certainly supported.  The code below would work "as expected" and the "divide by zero" exception would be marshaled back.
>
> RemoteInterface<SomeClass> ri("my.named.service");
>
> try {
>        float rtn = ri.divide( 5, 0 );
> } catch ( const std::exception& e )
> {
>        ..
> }
>
> The asynchronous interface would be:
>
> future<float> rtn = ri.divide( 5, 0,  AsyncFlag );
> ri.divide( 5, 0,  AsyncFlag | NoReturn );
> future<float> rtn2 = ri.divide( 5, 0,  AsyncFlag );
>
> try {
> if( !rtn.wait(timeout) ) { err...timeout }
> } catch ( const std::exception& e ) { divide by zero caught async }
>
> float auto_cast = rtn2;
>
> Earlier versions of the library used a meta-object system similar to mirror and I ended up with "slow" code that looked something like:
>
> ri.invoke( "float divide(float,float)", 5, 0 );
>
> That approach was error prone (no compile time checks on signature).  So I replaced it with:
>
> ri.invoke( SLOT(SomeClass,divide), 5, 0 );
>
> But I realized I was providing all of the compile time information necessary to optimize the serialization yet the implementation was still
> dependent upon polymorphic functions dealing with "generic" parameters.  Plus, my ultimate goal was to make using the remote object
> as seamless/similar to using the local object as possible.   Thus what I really needed was the concept of a  "proxy" object that provided
> all of the same methods as the "real object" and then provided a means to "delegate" the actual invocation of those methods.
>
> You will notice that whether it is dbus, corba, etc they all have the fundamental layer that looks something like:
>
> ri.invoke( "float divide(float,float)", 5, 0 );
>
> And then they use code generation or manual implementation to create a "proxy class" that has real methods that then invoke the fundamental layer to hide the
> messy invocation details from the user of the remote object.
>
> The META_INTERFACE(...) macro defines a generic "Proxy Template"  that can then be specialized for different kinds of back-ends via a delegate template parameter.
>
> template<typename SomeClass, typename SomeDelegate=DefaultDelegate>
> MetaInterface : ...
>
> The default delegate simply takes a pointer to the "real object" and would enable local scripting engines or the server side of a RPC library.
>
> The RemoteInterfaceDelegate replaces the call to the "real object" with a remote procedure call using your "protocol of choice".   You would have a different RemoteInterfaceDelegate
> for XML-RPC, Corba, dbus... etc
>
> In reality what I believe I have achieved is automatic generation of proxy classes without the use of an "interface description language", "Qt moc compiler", or other code generation schemes outside of standard C++.  With this auto-generation the "fundamental layer" gets full access to all of the type info and thus can implement very efficient in-line serialization/deserialization of parameters and return values.
>
> Obviously, the library will need a lot of work to fit with boost naming conventions and I will need some help with macros to auto-define all combinations of parameters (currently 0-8 are supported, but manually defined).
>
> Dan
>
>
>
>
>
>
>
>
>
>
>
>
> On Feb 7, 2010, at 6:55 AM, Matus Chochlik wrote:
>
>> On Sun, Feb 7, 2010 at 12:52 PM, Matus Chochlik <chochlik_at_[hidden]> wrote:
>>> On Sun, Feb 7, 2010 at 3:52 AM, Daniel Larimer <dlarimer_at_[hidden]> wrote:
>>>> I have been playing with some code and recently developed a very efficient, extensible, and easy to use API for performing remote procedure calls (with multiple protocols).   I am writing to gauge interest and get feedback on the user API.  The native "protocol" is a custom combined tcp/udp protocol using multi-cast for discovery, but it would be very easy to add a shared memory solution, a dbus, XML/RPC, CORBA, etc back end to the user api.
>>>>
>>> [snip]
>>>>
>>>> META_INTERFACE( SomeClass,
>>>>        METHOD(add)
>>>>        METHOD(sub)
>>>>        METHOD(inout)
>>>> )
>>>>
>>> Concerning this meta-interface declaration you might want to take a look at
>>> the Mirror library, which can provide a lot of meta-data at both compile-time
>>> and run-time.
>>>
>>> Both the C++98 and C++0x versions are in the Boost Vault and the C++0x
>>> version can be also found on sourceforge:
>>> http://sourceforge.net/projects/mirror-lib/
>>>
>>> the docs for the new version can be found here (though they are nowhere
>>> near to finished, yet)
>> here (sorry):  http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/
>>>
>>> [snip]
>>>
>> BR
>>
>> matus
>> _______________________________________________
>> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>

-- 
________________
::matus_chochlik

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk