I’m coming from Classic Actors and I’m learning Typed Actors. I’d like to gain some more intuition about the relationship between the ActorContext and a Behavior.
With classic Actors it is clear what an Actor is. An actor is literally an Actor instance. Ironically, with Typed Actors we no longer have any actors, it seems. We only have Behaviors and ActorContexts.
I can create a Behavior that doesn’t have an ActorContext, and I believe I can create multiple ActorContexts for a single Behavior by nesting setups (even though I think this is not intended). The Behavior that has access to a context can change.
Coming from classic Actors, how can I gain some intuition of what an ActorContext is? Where are the boundaries where an Actor begins and ends? What owns an ActorContext / what does an ActorContext own?
The ActorContext is always 1:1 with instance of an actor, when an actor has been started it exists even if you do not access it in any behavior that the actor has during its lifetime. When the actor is stopped and is garbage collected, so is the actor context. Multiple nested setup blocks will just give access to the same actor context and is not a problem.
You can think of the ActorContext as parallel to what ActorRef is for the actor from the “outside”, but from the “inside”. It gives access to operations that are associated with the actor instance, for example spawning children, emitting log entries etc. that should only ever be used by the current behavior of the actor.
The definition of an actor is a computational entity that in response to a message can:
send messages to other actors
create new actors
change its state
designate the behavior to be used for the next message it receives
In Akka this boils down to a running actor having a current behavior to use when receiving the next message, access to a way to spawn children and optional state.
In the classic API this is directly and always modelled as a class (Actor for Scala and AbstractActor for Java). While this at first glance seems simple the running actor is in fact more of a pair of the actor class instance and the actor context (which for example contains the current behavior Receive, self).
In the new APIs this can be modelled both in the same way using a class based AbstractBehavior which the actor keeps for its entire life with state modelled as mutable fields, but also with a more FP:ish-style where the behavior and state is separated and the actor often returns a new behavior and state pair in response to a message. The running actor is in this case also essentially a pair of the actor context and the current behavior.
If you look at the current implementation of the new APIs you can see that it is in fact built on top of the classic APIs, spawning a typed actor always spawns a classic actor under the hood.
Fantastic explanation, thank you very much. It fully answers my question and gives me clear understanding how to manage ActorContext instances. Nothing stopping me now from building an amazing Akka Typed application ;)
This is how I have now summarized it for myself based on the post above: The ActorContext is the continuing Identity of the actor, independent of state and behavior.