Our Sheep class is an arbitrary C++ class that defines some attributes for a sheep's color, weight and so on as well as several methods that act either as predicates (such as isBlack(), isWhite() ) or return/change some of the sheep's attributes ( such as weight() and feed()).
enum Color { Black, White }; class Sheep { public: Sheep(Color col, int weight) { my_color = col; my_weight = weight; } Color color() { return my_color; } bool isBlack() { return color() == Black; } bool isWhite() { return color() == White; } int weight() { return my_weight; }
int feed (int food) { return my_weight += food; } private: Color my_color; int my_weight; };
The following piece of code shows us, how we can create and access instances of Sheep remotely using TACO.
// C++
Sheep *sheep = new Sheep(Black, 47);
int kg = sheep->feed(18);
// the TACO equivalent
#include "Sheep.h"
#include "taco/taco.h"
ObjectPtr<Sheep> sheep = allocate<Sheep> (17) (Black, 47);
int kg = sheep->invoke( m2f(&Sheep::feed, 18) );
Note, that the expression &Sheep::feed evaluates to a so-called pointer to member function which will be implicitly evaluated to a method slot number when the method is declared as a virtual method. Thus even the invocation of a virtual method works remotely in the same way as it would work locally. This allows us to construct polymorphic distributed data-structures.
Parameter passing is strictly call-by-value and global object pointers can be passed as well. Note, that a local pointer is automatically converted to its corresponding global object pointer, when the formal parameter list of the specified method declares the parameter to be a global pointer type. Thus we can pass effectively pointers to local objects to remote sites, that are now able to perform indirect recursive call-backs or create dynamic distributed data structures semantically the same way as if they were in local memory.
TACO's basic RMI layer defines the following remote invocation primitives:
ptr = allocate<Class>(where)(args);
r = ptr->invoke(functor);
ptr->call(void-functor);
ptr->apply(void-functor);
ptr->apply(functor,sync);
...
r = sync; // lazy synchronization
Note, that the basic remote invocation mechanisms are entirely orthogonal to the object's type, because we wanted to be able to invoke arbitrary methods on arbitrary objects with a similar semantic as a corresponding local invocation. Consequently, all method invocations are potentially concurrent and indirect recursive invocations across the network are possible as well. However, concurrent invocations accessing the same object instance are not automatically synchronized.