This is really great! Your library would be totally useless without a good doc, since it's so much different from any "common" library. It really looks like more a new language integrated in C++ then a library.
You often speak about network transparency and automatic serialization of objects. Is that feature already working? I am very interested in this as I need to use a networking-friendly actor library. I was thinking to roll my own simple implementation but yours look really fully-featured.
On a side note, I still don't fully grasp what can be done with your "receive" construct (like what the limits are? Can I "nest" receive constructs?), but that I will ask another time.
I designed libcppa as an internal DSL, so it was my intention to give it that feeling. I think it makes the code much simpler, shorter and cleaner. Sadly, there are clear limitations in C++ for internal DSL. Just have a look at the receive_while statement. Using a lambda as condition is the best you can do (and no: macro-magic is not an option). But it polluts your source code with brackets and a return. One cannot come closer to a "native" while loop in C++ unlike Scala btw. where you can implement a library that is looking like a language extension or even another language: http://www.scala-lang.org/node/1403.
Network transparency is implemented and working. All you need to do is to "publish" an actor to a port. Afterwards, you use "remote_actor" to get an actor_ptr to the published actor. I don't have an example now but it's really simple:
auto my_actor = spawn(...); publish(my_actor, 4242);
... (an another process or node) ... auto my_actor = remote_actor("localhost", 4242);
To answer your side node question: there are no limitations. You can nest receives as much as you like since actors do have their own stacks.
One other question: can I make an actor out of a class? For example, I might want to have my actor to call methods of my class, and such. Sure I can create a local instance of my class inside the function used when creating an actor, and then call methods by m_instance.myMethod(), but I don't like it very much... Also, is there any better place then those comments for asking questions? I also found a little problem when compiling (make stops at the examples, easily fixable I think), but I prefer not to post long messages here.
Nevermind, I needed to read the docs with more attention: you can use functors with spawn, so yes, you can use your own class as actors. Just one question: when I spawn an actor by using a functor, a brand new copy instance is created using the copy constructor, right? So if I want I can then delete the object used in spawn with no risks. (EG: going out of scope!)
Ah. This feature recently changed (git pull!) so I couldn't update the documentation yet. However, there is a class called "scheduled_actor". Derive this class if you want to use a class-based actor implementation. A short snippet:
#include #include #include "cppa/cppa.hpp" using namespace cpp;
void on_exit() { // ... some cleanup code ... // do not send or receive message here any longer!
}
};
int main() { auto a = spawn(new my_actor); send(a, atom("hello"), "world"); return 0; }
But It's also fine to use a functor. You should be able to use a move constructor to avoid unnecessary copies. However, if not moved to the scheduler, the functor is copied, yes. No dangling pointer.
There is also a second way to implement class-based actors that uses event-based message processing. There'll be a blog post and a documentation update soon. :)
Btw, you just can send me emails if you don't want to post here or create a ticket on github if you find a bug.
ChangeNote for version 0.2: You have to subtype context_switching_actor and override run() instead of act(). However, I would recommend to use always event_based_actor for performance reasons.
This is really great! Your library would be totally useless without a good doc, since it's so much different from any "common" library. It really looks like more a new language integrated in C++ then a library.
ReplyDeleteYou often speak about network transparency and automatic serialization of objects. Is that feature already working?
I am very interested in this as I need to use a networking-friendly actor library. I was thinking to roll my own simple implementation but yours look really fully-featured.
On a side note, I still don't fully grasp what can be done with your "receive" construct (like what the limits are? Can I "nest" receive constructs?), but that I will ask another time.
I designed libcppa as an internal DSL, so it was my intention to give it that feeling. I think it makes the code much simpler, shorter and cleaner. Sadly, there are clear limitations in C++ for internal DSL. Just have a look at the receive_while statement. Using a lambda as condition is the best you can do (and no: macro-magic is not an option). But it polluts your source code with brackets and a return. One cannot come closer to a "native" while loop in C++ unlike Scala btw. where you can implement a library that is looking like a language extension or even another language: http://www.scala-lang.org/node/1403.
ReplyDeleteNetwork transparency is implemented and working. All you need to do is to "publish" an actor to a port. Afterwards, you use "remote_actor" to get an actor_ptr to the published actor. I don't have an example now but it's really simple:
auto my_actor = spawn(...);
publish(my_actor, 4242);
... (an another process or node) ...
auto my_actor = remote_actor("localhost", 4242);
To answer your side node question: there are no limitations. You can nest receives as much as you like since actors do have their own stacks.
One other question: can I make an actor out of a class? For example, I might want to have my actor to call methods of my class, and such.
ReplyDeleteSure I can create a local instance of my class inside the function used when creating an actor, and then call methods by m_instance.myMethod(), but I don't like it very much...
Also, is there any better place then those comments for asking questions? I also found a little problem when compiling (make stops at the examples, easily fixable I think), but I prefer not to post long messages here.
Nevermind, I needed to read the docs with more attention: you can use functors with spawn, so yes, you can use your own class as actors. Just one question: when I spawn an actor by using a functor, a brand new copy instance is created using the copy constructor, right? So if I want I can then delete the object used in spawn with no risks. (EG: going out of scope!)
ReplyDeleteAh. This feature recently changed (git pull!) so I couldn't update the documentation yet. However, there is a class called "scheduled_actor". Derive this class if you want to use a class-based actor implementation. A short snippet:
ReplyDelete#include
#include
#include "cppa/cppa.hpp"
using namespace cpp;
class my_actor : public scheduled_actor
{
public:
void act()
{
receive
(
on() >> [](const std::string& str)
{
std::cout << "hello " << str << std::endl;
}
);
}
void on_exit()
{
// ... some cleanup code ...
// do not send or receive message here any longer!
}
};
int main()
{
auto a = spawn(new my_actor);
send(a, atom("hello"), "world");
return 0;
}
But It's also fine to use a functor. You should be able to use a move constructor to avoid unnecessary copies. However, if not moved to the scheduler, the functor is copied, yes. No dangling pointer.
There is also a second way to implement class-based actors that uses event-based message processing. There'll be a blog post and a documentation update soon. :)
Btw, you just can send me emails if you don't want to post here or create a ticket on github if you find a bug.
Sorry, I messed up formatting:
ReplyDelete#include <string>
#include <iostream>
#include "cppa/cppa.hpp"
using namespace cpp;
class my_actor : public scheduled_actor
{
public:
void act()
{
receive
(
on() >> [](const std::string& str)
{
std::cout << "hello " << str << std::endl;
}
);
}
void on_exit()
{
// ... some cleanup code ...
// do not send or receive message here any longer!
}
};
int main()
{
auto a = spawn(new my_actor);
send(a, atom("hello"), "world");
return 0;
}
ChangeNote for version 0.2: You have to subtype context_switching_actor and override run() instead of act(). However, I would recommend to use always event_based_actor for performance reasons.
Delete