$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] Is there any interest in a library for actor	programming?
From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2013-05-20 20:02:42
> There was some discussion about this topic after the talk at the C++Now
> conference. I do agree that it is desirable to enable the compiler to
> verify the correctness of actor programs at compile time. However, in
> order to be able to ensure the correctness of a program, one would have to
> define not only all possible input messages, but the response types
> depending on the input as well. Consider this example:
> 
> actor_type<reacts_to<atom("add"),int,int>::with<int>,
>            reacts_to<atom("hello")>::with<std::string>> my_actor() {
>     return (
>         on(atom("add"), arg_match) >> [](int a, int b) {
>             return a+b;
>         },
>         on(atom("hello")) >> [] {
>             return "world";
>         }
>     );
> }
> 
> It's easy to check whether the interface is fulfilled. On each send, the
> compiler is able to check whether the given message matches actor_type and
> if the sender of the message (more precisely, the receiver of the response
> message) can handle the result. However, an approach like this cannot
> allow an actor to change its behavior. Hence, something as simple as the
> classical dining philosophers example
> (https://github.com/Neverlord/libcppa/blob/master/examples/message_passing
> /dining_philosophers.cpp) is not possible.
> 
> So, what if we allow actors to set a subset of given actor_type as
> behavior? Consider this example:
> 
> struct my_actor : actor_type<reacts_to<atom("init">,
>                              reacts_to<atom("add"),int,int>::with<int>,
>                              reacts_to<atom("hello")>::with<std::string>>
> {
>     void init() {
>         // check whether given match_expr defines a subset of defined
> actor_type
>         become (
>             on(atom("init")) >> [=] {
>                 become (
>                     on(atom("add"), arg_match) >> [=](int a, int b) {
>                         return a+b;
>                     },
>                     on(atom("hello")) >> [=] {
>                         return "world";
>                     }
>                 );
>             }
>         );
>     }
> }
> 
> This approach only allows class-based actors, because we need to evaluate
> the type information provided by 'this'. We would enable the compiler to
> check for *some* errors, but we could not verify, at compile time, that an
> actor actually implements its own interface, because we have no way the
> check whether an actor implements a message handler for each message it
> claims to be able to receive.
> 
> Even worse, both approaches do not allow actors to send/receive messages
> before replying to a request (unless message passing would be blocking,
> which would put an end to scalability). If we go back to the reply() API
> currently found in libcppa, we couldn't match request and response type.
> 
> 
> In any case, we would no longer be able to converts threads to actors on-
> the-fly:
> 
> int main() {
>     auto worker = spawn(...);
>     // Um... what is the type of 'self'? Is it a valid receiver for the
> response message?
>     send(worker, ...);
>     receive (
>         // again: what is 'self' allowed to receive/reply? ...
>     );
> }
> 
> 
> Long story short: a type-safe interface would be less powerful and would
> require more boilerplate code. However, perhaps there is a middle ground
> for doing type checks at runtime when compiled in debug mode?
> 
> int my_actor() {
>     // macro, defined as nothing if not compiled in debug mode
>     assert_protocol(reacts_to<atom("add"),int,int>::with<int>,
>                     reacts_to<atom("hello")>::with<std::string>);
> }
> 
> Perhaps it would be possible to include the first presented approach for
> type-safe actors along with the (dynamic) default actor API. In this way,
> we could compose type-safe subsystems of actors whenever a problem can be
> solved using the limited API.
Even if I have to admit that I don't understand all implication of what
you're saying, I would like to assert that it is possible to expose a fully
compile-time type-safe way of invoking remote functions (actors). Here is
what we do in HPX (https://github.com/STEllAR-GROUP/hpx/):
    int foo(std::string s) { return boost::lexical_cast<int>(s); }
    typedef hpx::make_action<decltype(&foo), &foo>::type foo_action_type;
    foo_action_type foo_action;
    // 'synchronous' invocation
    cout << foo_action(remote_locality_id, "42");       // prints 42
    // asynchronous invocation
    hpx::future<int> f = hpx::async(foo_action, remote_locality_id, "42");
    // do other stuff
    cout << f.get();       // prints 42
    // fails compiling
    cout << foo_action(remote_locality_id, 42);
The same (similar) works for invoking member functions of remote objects.
Regards Hartmut
---------------
http://boost-spirit.com
http://stellar.cct.lsu.edu