To answer your questions slightly out of order: CAF has two kinds of actors: statically typed and dynamically typed. You have probably already used the latter ones. The main difference is that statically typed actors use `typed_actor<...>` handles. Here is a small snippet that also is an example for your first question:
using array_actor = typed_actor<replies_to<uint32_t>
::with_either<ok_atom, std::string>
::or_else<error_atom, std::string>>;
array_actor::behavior_type array_actor_impl() {
auto data = std::make_shared<std::vector<std::string>>();
data->push_back("one");
data->push_back("two");
return {
[=](uint32_t index) -> either<ok_atom, std::string>
::or_else<error_atom, std::string> {
if (index >= data->size())
return {error_atom::value, "index out of bounds"};
return {ok_atom::value, data->at(index)};
}
};
}
void some_function() {
auto aut = spawn_typed(array_actor_impl);
scoped_actor self;
self->sync_send(aut, uint32_t{0}).await(
[](ok_atom, const std::string& str) {
assert(str == "one");
},
[](error_atom, const std::string& err) {
std::cerr << "error: " << err << std::endl;
}
);
}
A pattern we often use in CAF for operations that might fail is to respond with either 'ok' or 'error' messages. In this particular case, optional<string> as result type is perfectly fine and will require less code an the caller side. If you copy & paste the example and play a bit around with it, you will see that the compiler will create errors for sending a wrong message to or expecting wrong results from the typed actor.