Actor State Management
Relevant source files
The following files were used as context for generating this wiki page:
Actor State Management in Sploosh provides a model for concurrent execution that eliminates shared mutable state bugs by utilizing isolated units called Actors. Each actor maintains its own private state and processes incoming messages from its own mailbox, combining Elixir-style supervised concurrency with Rust-style memory safety.
The system ensures that mutable state is never shared between concurrent units. Instead, actors communicate via message passing, where internal state transitions occur only within the actor's context in response to a received message or a request/reply interaction.
Sources: VISION.md:7-13, README.md:34-40
Architecture and Core Components
The Actor system is built on isolation. An actor is an isolated unit of execution containing private fields (state) and handlers (behavior). Communication with an actor is performed through a Handle<T>, which is a reference that can be safely cloned and sent across execution boundaries.
Actor Definition Structure
An actor definition consists of two primary parts:
- State Fields: Private variables that define the actor's internal data.
- Handlers: Functions that define how the actor responds to messages.
The diagram above illustrates the structural relationship between an Actor, its state fields, and its message handlers as defined in the AST.
Sources: crates/sploosh-ast/src/lib.rs:118-132, crates/sploosh-parser/src/lib.rs:252-290
Interaction Methods
Actors support two primary modes of interaction:
- Fire-and-forget (
send): Asynchronous message passing that does not block the sender. - Request/Reply: Synchronous calls that block the sender until the actor returns a value.
| Component | Description | Syntax/Keyword |
|---|---|---|
Handle<T> | A Clone + Send reference to a running actor. | let h: Handle<Actor> |
spawn | Instantiates and starts a new actor instance. | spawn Actor::init() |
send | Dispatches an asynchronous message to an actor's mailbox. | send handle.msg() |
&mut self | Used in handlers to allow mutation of internal actor state. | pub fn inc(&mut self) |
Sources: VISION.md:88-92, README.md:35-50, crates/sploosh-parser/src/lib.rs:467-483
Data Flow and Message Handling
Messages in Sploosh are processed sequentially by the actor. When an actor receives a message, it executes the corresponding handler. If the handler is marked with &mut self, it is granted exclusive mutable access to the actor's internal fields.
Message Processing Flow
This flowchart describes the lifecycle of a message from the point of dispatch to the internal state modification within the actor.
Sources: README.md:34-48, crates/sploosh-parser/src/lib.rs:467-483
Mailbox Management
Handlers can be configured with attributes to control mailbox behavior, such as capacity. The @mailbox attribute is parsed and preserved in the AST to inform the runtime of these constraints.
actor Worker {
state: i64,
@mailbox(capacity: 2048)
pub fn run(&mut self, n: i64) {
self.state = self.state + n;
}
}
Sources: crates/sploosh-parser/src/lib.rs:1049-1055, crates/sploosh-ast/src/lib.rs:129-132
Concurrency Safety Rules
Sploosh enforces strict rules to prevent shared-state bugs:
- No Shared Mutable State: Actors are the only way to express mutable state that needs to be accessed by multiple parts of a system.
- Ownership Internal to Actor: Rust-style ownership exists inside each actor, but data passed between actors via messages follows strict transfer or ref-counting rules.
Shared<T>Primitives: The only way to share immutable data without an actor is throughShared<T>, a ref-counted primitive.- Send Restriction: The
sendkeyword is restricted at the statement head. Its operand must be a method call on a handle, ensuring messages target specific actor interfaces.
Sources: VISION.md:58-62, VISION.md:92-94, crates/sploosh-parser/src/lib.rs:467-483
Parser Implementation of Actor Syntax
The sploosh-parser implements actor definitions by identifying the actor keyword and processing a brace-delimited block containing fields and handlers.
- Field Parsing: Identifies identifiers followed by a colon and a type. Fields are private by default.
- Handler Parsing: Identifies function definitions (
fn_def). Handlers can be markedpub,async, or prefixed with attributes. - State Access: The parser recognizes
&mut selfand&selfreceivers to differentiate between state-mutating and read-only handlers.
Sources: crates/sploosh-parser/src/lib.rs:252-290, crates/sploosh-parser/src/lib.rs:163-176
Summary
Actor State Management in Sploosh serves as the primary mechanism for building concurrent systems without the risks associated with shared mutable state. By isolating state within Actors and requiring explicit message passing via Handle<T>, the language provides a structured, safety-first approach to concurrency. This model is supported by the compiler frontend through specific AST nodes for actors, handlers, and the send statement, ensuring that the design principles of structural concurrency are enforced from the parsing stage.
Sources: VISION.md:9-13, AGENTS.md:144-148