tags:

views:

1032

answers:

5

Actually, this question seems to have two parts:

  • How to implement pattern matching?
  • How to implement send and receive (i.e. the Actor model)?

For the pattern matching part, I've been looking into various projects like App and Prop. These look pretty nice, but couldn't get them to work on a recent version (4.x) of g++. The Felix language also seems to support pattern matching pretty well, but isn't really C++.

As for the Actor model, there are existing implementations like ACT++ and Theron, but I couldn't find anything but papers on the former, and the latter is single-threaded only [see answers].

Personally, I've implemented actors using threading and a thread-safe message queue. Messages are hash-like structures, and used these together with a number of preprocessor macros to implemented simple pattern matching.

Right now, I can use the following code to send a message:

(new Message(this))
    ->set("foo", "bar")
    ->set("baz", 123)
    ->send(recipient);

And the following to do simple pattern matching (qDebug and qPrintable are Qt-specific):

receive_and_match(m)
    match_key("foo")    { qDebug("foo: %s", qPrintable(m->value("foo").toString())); }
    or_match_key("baz") { qDebug("baz: %d", m->value("baz").toInt()); }
    or_match_ignore
end_receive

However, this looks a bit hackish to me, and isn't very robust.

How would you do it? Did I miss any existing work?

+2  A: 

One of the important things about erlang is how the features are used to make robust systems.

The send/recieve model is no-sharing, and explicitly copying. The processes themselves are lightweight threads.

If you did desire the robust properties of the erlang model, you would be best to use real processes and IPC rather than threads.

If you want robust message passing though you may end up wanting to serialize and deserialise the contents. Especially with type safety.

Pattern matching in C++ isn't always pretty but there will be a good pattern for this - you will end up creating a dispatcher object that uses some form of polymorphism to get what you want.

Although if you are not careful you end up with xml over pipes :)

Really, if you want the erlang model you really want to use erlang. If there are slow bits, I'm sure you can augment your program using a foreign function internet.

The problem about re-implementing parts, is you won't get a good cohesive library and solution. The solutions you have already don't look much like C++ anymore.

1729
+3  A: 

As for the Actor model, there are existing implementations like ACT++ and Theron, but I couldn't find anything but papers on the former, and the latter is single-threaded only.

As the author of Theron, I was curious why you believe it's single-threaded?

Personally, I've implemented actors using threading and a thread-safe message queue

That's how Theron is implemented.. :-)

Ash

To be honest, I have no clue why I figured Theron was single-threaded. Re-reading the website doesn't give me that impression at all. My apologies for the confusion, and I think it would be fair if I gave Theron another shot!
Maarten Sander
+2  A: 

I'm currently implementing an actor library for C++ called "acedia" (there's nothing yet about it on google) that uses "type matching". The library is a project for my master thesis and you can send any kind of data to an actor with it.

A small snippet:

recipient.send(23, 12.23f);

And on the recipient side you can either analyze the received message like this:

Message msg = receive();
if (msg.match<int, float>() { ... }

... or you can define a rule set that invokes a function or method for you:

void doSomething(int, float);

InvokeRuleSet irs;
irs.add(on<int, float>() >> doSomething);
receiveAndInvoke(irs);

It's also possible to match both on type and on value:

Message msg = receive();
if (msg.match<int, float>(42, WILDCARD) { ... }
else if (msg.match<int, float>() { ... }

The constant "WILDCARD" means, that any value will be acceptet. Pass no arguments is equal set all arguments to "WILDCARD"; meaning that you only want to match the types.

This is certainly a small snippet. Also you can use "case classes" like in Scala. They are comparable to "atomics" in erlang. Here is a more detailed example:

ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage)
ACEDIA_DECLARE_CASE_CLASS(Event1)
ACEDIA_DECLARE_CASE_CLASS(Event2)

To react to the defined case classes you can write an actor like this:

class SomeActor : public Actor
{

  void shutdown() { done = true; }
  void handleEvent1();
  void handleEvent1();

  public:

    SomeActor() : done(false) { }

    virtual void act()
    {
      InvokeRuleSet irs;
      irs
        .add(on<ShutdownMessage>() >> method(&SomeActor::shutdown))
        .add(on<Event1>() >> method(&SomeActor::handleEvent1))
        .add(on<Event2>() >> method(&SomeActor::handleEvent2))
      ;
      while (!done) receiveAndInvoke(irs);
    }

};

To create a new actor and start it, all you have to write is:

Acedia::spawn<SomeActor>();

Although the library not even reached beta stadium the shown snippets work and i have a first application running on it. One major goal of the library is to support distributed programming (also across a network).

Your question is a while ago, but if you're interested in it: let me know! :)

neverlord
I'm definately interested; it looks pretty nice. Is there a website where I can download the library/view the docs? Will you be open sourcing it?
Maarten Sander
A: 

I would definitely be interested in looking at your "acedia" library and would love to help in any way that I could. Erlang has some wonderful constructs and C++ could definitely benefit from such a library.

A: 

Today I hostet the library at sourceforge: https://sourceforge.net/projects/acedia/

As I said before it's an early release. But feel free to critique it!

neverlord
I've downloaded it, and I'll try it out as soon as I get the chance.
Maarten Sander