Thursday, May 26, 2011

acedia and libcppa

If you're interested in actor programming and C++, you might have found acedia on sourceforge. And maybe you've noted, that I'm the author of both acedia (which is dead now) and libcppa. But why should one "throw away" such an amount of work?

First: acedia is an "intrusive library". If you're looking through the acedia examples, you'll note that you have to write a lot of gluecode (derive from acedia::Actor, override act(), use stuff like .unbox(), etc.). It's not convenient and you have to write too much code for simple tasks. Second: some parts of the library needed a redesign (e.g. serialization and MetaClass). Third: acedia had too much preprocessor magic and horrible code smells (basically because of the lack of variadic templates: send() had 10 overloads, Tuple had 10 template specializations, etc.).

So I decided to start from scratch again (and move to C++0x). Just compare the acedia pong example with this equivalent libcppa code:

using namespace cppa;
using namespace cppa::placeholders;

void pong(actor_ptr ping_actor)
{
  link(ping_actor);
  bool done = false;
  // kickoff
  send(ping_actor, 0);
  // receive loop
  do_receive
  (
    on<int>().when(_x1 > 9) >> [&]() {
      done = true;
    },
    on<int>() >> [](int v) {
      reply(v+1);
    }
  )
  .until(gref(done));
  // terminate with non-normal exit reason
  // to force linked ping actor to quit
  quit(user_defined_exit_reason);
}

void ping()
{
  receive_loop
  (
    on<int>() >> [](int v)
    {
      reply(v+1);
    }
  );
}

int main()
{
    spawn(pong, spawn(ping));
    await_all_others_done();
    return 0;
}

libcppa is designed as an internal DSL (btw: that's the reason why I switched from CamelCase to the STL coding conventions). That makes the code much clearer, less verbose and you don't have to hack around with stuff like MockActor. Everything (even main) is implicitly converted to an actor if needed without a single line of extra-code.