--- title: "Actors and Modules" description: "The ƿit execution model" weight: 20 type: "docs" --- ƿit organizes code into two types of scripts: **modules** (`.cm`) and **actors** (`.ce`). ## The Actor Model ƿit is built on the actor model of computation. Each actor: - Has its own **isolated memory** — actors never share state - Runs to completion each **turn** — no preemption - Performs its own **garbage collection** - Communicates only through **message passing** This isolation makes concurrent programming safer and more predictable. ## Modules (.cm) A module is a script that **returns a value**. The returned value is cached and frozen (made stone). ```javascript // math_utils.cm var math = use('math/radians') var distance = function(x1, y1, x2, y2) { var dx = x2 - x1 var dy = y2 - y1 return math.sqrt(dx * dx + dy * dy) } var midpoint = function(x1, y1, x2, y2) { return { x: (x1 + x2) / 2, y: (y1 + y2) / 2 } } return { distance: distance, midpoint: midpoint } ``` **Key properties:** - **Must return a value** — it's an error not to - **Executed once per actor** — subsequent `use()` calls return the cached value - **Return value is stone** — immutable, safe to share - Modules can import other modules with `use()` ### Using Modules ```javascript var utils = use('math_utils') var d = utils.distance(0, 0, 3, 4) // 5 ``` ## Actors (.ce) An actor is a script that **does not return a value**. It runs as an independent unit of execution. ```javascript // worker.ce print("Worker started") $receiver(function(msg) { print("Received:", msg) send(msg, {status: "ok"}) }) ``` **Key properties:** - **Must not return a value** — it's an error to return - Has access to **actor intrinsics** (functions starting with `$`) - Runs until explicitly stopped or crashes ## Actor Intrinsics Actors have access to special functions prefixed with `$`: ### $self Reference to the current actor. This is a stone (immutable) actor object. ```javascript print($self) // actor reference print(is_actor($self)) // true ``` ### $overling Reference to the parent actor that started this actor. `null` for the root actor. Child actors are automatically coupled to their overling — if the parent dies, the child dies too. ```javascript if ($overling != null) { send($overling, {status: "ready"}) } ``` ### $stop() Stop the current actor. When called with an actor argument, stops that underling (child) instead. ```javascript $stop() // stop self $stop(child) // stop a child actor ``` ### $start(callback, program) Start a new child actor from a script. The callback receives lifecycle events: - `{type: "greet", actor: }` — child started successfully - `{type: "stop"}` — child stopped cleanly - `{type: "disrupt", reason: ...}` — child crashed ```javascript $start(function(event) { if (event.type == 'greet') { print("Child started:", event.actor) send(event.actor, {task: "work"}) } if (event.type == 'stop') { print("Child stopped") } if (event.type == 'disrupt') { print("Child crashed:", event.reason) } }, "worker") ``` ### $delay(callback, seconds) Schedule a callback after a delay. Returns a cancel function that can be called to prevent the callback from firing. ```javascript var cancel = $delay(function() { print("5 seconds later") }, 5) // To cancel before it fires: cancel() ``` ### $clock(callback) Get called every frame/tick. The callback receives the current time as a number. ```javascript $clock(function(t) { // called each tick with current time }) ``` ### $receiver(callback) Set up a message receiver. The callback is called with the incoming message whenever another actor sends a message to this actor. To reply to a message, call `send(message, reply_data)` — the message object contains routing information that directs the reply back to the sender. ```javascript $receiver(function(message) { // handle incoming message send(message, {status: "ok"}) }) ``` ### $portal(callback, port) Open a network port to receive connections from remote actors. ```javascript $portal(function(connection) { // handle new connection }, 8080) ``` ### $contact(callback, record) Connect to a remote actor at a given address. ```javascript $contact(function(connection) { // connected }, {host: "example.com", port: 80}) ``` ### $time_limit(requestor, seconds) Wrap a requestor with a timeout. Returns a new requestor that will cancel the original and call its callback with a failure if the time limit is exceeded. See [Requestors](/docs/requestors/) for details. ```javascript var timed = $time_limit(my_requestor, 10) timed(function(result, reason) { // reason will explain timeout if it fires }, initial_value) ``` ### $couple(actor) Couple the current actor to another actor. When the coupled actor dies, the current actor also dies. Coupling is automatic between a child actor and its overling (parent). ```javascript $couple(other_actor) ``` ### $unneeded(callback, seconds) Schedule the actor for removal after a specified time. The callback fires when the time elapses. ```javascript $unneeded(function() { // cleanup before removal }, 30) ``` ### $connection(callback, actor, config) Get information about the connection to another actor. For local actors, returns `{type: "local"}`. For remote actors, returns connection details including latency, bandwidth, and activity. ```javascript $connection(function(info) { if (info.type == "local") { print("same machine") } else { print(info.latency) } }, other_actor, {}) ``` ## Runtime Functions These functions are available in actors without the `$` prefix: ### send(actor, message, callback) Send a message to another actor. The message must be an object record. The optional callback receives the reply when the recipient responds. ```javascript send(other_actor, {type: "ping"}, function(reply) { print("Got reply:", reply) }) ``` To reply to a received message, pass the message itself as the first argument — it contains routing information: ```javascript $receiver(function(message) { send(message, {result: 42}) }) ``` Messages are automatically flattened to plain data. ### is_actor(value) Returns `true` if the value is an actor reference. ```javascript if (is_actor(some_value)) { send(some_value, {ping: true}) } ``` ### log Channel-based logging. Any `log.X(value)` writes to channel `"X"`. Three channels are conventional: `log.console(msg)`, `log.error(msg)`, `log.system(msg)` — but any name works. Channels are routed to configurable **sinks** (console or file) defined in `.cell/log.toml`. See [Logging](/docs/logging/) for the full guide. ### use(path) Import a module. See [Module Resolution](#module-resolution) below. ### args Array of command-line arguments passed to the actor. ### sequence(), parallel(), race(), fallback() Requestor composition functions. See [Requestors](/docs/requestors/) for details. ## Module Resolution When you call `use('name')`, ƿit searches: 1. **Current package** — files relative to package root 2. **Dependencies** — packages declared in `cell.toml` 3. **Core** — built-in ƿit modules ```javascript // From within package 'myapp': use('utils') // myapp/utils.cm use('helper/math') // myapp/helper/math.cm use('json') // core json module use('otherlib/foo') // dependency 'otherlib', file foo.cm ``` Files in the `internal/` directory are private to the package. ## Example: Simple Actor System ```javascript // main.ce - Entry point var config = use('config') print("Starting application...") $start(function(event) { if (event.type == 'greet') { send(event.actor, {task: "process", data: [1, 2, 3]}) } if (event.type == 'stop') { print("Worker finished") $stop() } }, "worker") $delay(function() { print("Shutting down") $stop() }, 10) ``` ```javascript // worker.ce - Worker actor $receiver(function(msg) { if (msg.task == "process") { var result = array(msg.data, function(x) { return x * 2 }) send(msg, {result: result}) } $stop() }) ``` ```javascript // config.cm - Shared configuration return { debug: true, timeout: 30 } ```