Hi Erdem,
I'm not entirely sure of what concern you are addressing here. It could be (a) the desire to use functions like `ask()` from within an Actor, (b) the desire to have the same API from within an Actor as from external code, or (c) something else.
With regards to (a):
Many actor system implementations mix in concepts like Futures and blocking that have their origins in synchronous programming environments or thread-based synchronization. This allows code inside the actor to perform operations like "ask", which will block until a response is received (either immediately, or when the corresponding Future value is needed).
I chose not to implement this type of functionality for Thespian because I believe it is fundamentally at odds with the Actor paradigm: an actor should respond to a message, and when it has finished that message it should be prepared to handle the next message (instead of being unavailable because it is blocked internally). This requires multi-part operations to be handled in a truly asynchronous manner, but from a systems level perspective provides better fidelity to the underlying paradigm and helps avoid system-responsible deadlocks in your Actor application. It also leads to a perception of 1:1 send/receive functionality for messages, but an Actor is a 1:N outbound only concept: every received message may cause the Actor to `send()` N outbound messages (where N is 0 to some reasonably large number), and there is no expectation of any responses to those messages (from a system level; your Actor implementation's "business logic" is up to you to define).
If you do wish your Actors to function in this type of blocking manner, you could provide that via a subclass layer between Thespian's `Actor` class and your target actor implementation. This intermediate subclass would receive messages and queue them internally to a "pending" queue, and the final implementation subclass would retrieve messages from this queue when ready to process something new. A "future" object would be handled by a separate "in-progress" queue in the intermediate subclass; while the "in-progress" queue was non-empty, no messages would be taken from the "pending" queue, and new incoming messages would be checked for satisfaction of a "future" on the "in-progress" queue before being placed on the "pending" queue. This is not an approach I would recommend, but provides a general sketch of an approach you wanted a blocking-style functionality for your implementation. The approach I would recommend is to attach any necessary resumption information to outbound messages that you expect to receive a response to; the receiving actor should maintain that information in the response such that the first actor can resume the operation using only the information in the response message (i.e. operation context is maintained in the exchanged messages, not within the actor's internal state).
With regards to (b):
External code operates in a conventional synchronous manner (possibly threaded) that does not allow it to be "interrupted" at any point when a message is available for it to process, thus the `ask()` and `listen()` functions provide endpoints where the synchronous external code can indicate a desire to receive a message. The `tell()` endpoint is the most direct analogy to the Actor's `send()` function, but here I felt that a different name would be good to clarify that it was an extra-Actor v.s. intra-Actor usage.
If you'd like more detail on any of the above, or if you were referencing something else entirely (option (c) above), please let me know and I'd be happy to address it.
Regards,
Kevin