Types & Errors

Turn's type system is designed for two goals: cognitive safety when working with LLM inference, and explicit error handling for stochastic failures. Every value in Turn has a known type, and the runtime enforces type constraints at both compile time and execution time.


The Type System

Turn is dynamically typed at the value level, with structural type checking enforced at inference boundaries. The table below lists every type in the language.

TypeDescription
NumIEEE 754 64-bit floating point number. All numeric values in Turn are doubles.
StrUTF-8 encoded string, reference-counted for efficient sharing across processes.
BoolBoolean value: true or false.
nullThe explicit absence of a value. Returned by recall when a key does not exist.
List<T>Ordered, growable collection. Supports indexing with list[i] and iteration.
Map<K, V>Key-value associative container. Keys may be strings or numbers.
StructNamed product type with typed fields, defined with struct Name { field: Type }.
CapOpaque capability handle. Unforgeable and non-serializable — used for permission control.
PidProcess identifier composed of a node_id and a local_id. Used for message passing.
Result<T, E>A value that is either Ok(T) on success or Err(E) on failure. Monadic.
Option<T>A value that is either Some(T) when present or None when absent.
Uncertain(T, f64)A value paired with a confidence score between 0.0 and 1.0.

Cognitive Type Safety

LLM inference is inherently stochastic — a model might return malformed output, omit required fields, or produce values that violate structural constraints. Turn addresses this with two mechanisms that make type safety enforceable even when the data source is non-deterministic.

infer Type

When you write infer Sentiment { prompt }, the Turn compiler generates a JSON Schema from the struct definition and sends it to the LLM as a response_format constraint. The LLM provider enforces the schema during generation. If the response still violates the schema (which can happen with weaker models), the VM automatically retries up to three times, injecting the validation error into the prompt as corrective feedback. This self-healing loop eliminates the need for manual JSON parsing and validation boilerplate.

Uncertain(T, confidence)

Some inference results carry a meaningful confidence score. The Uncertain type wraps a value with a floating-point confidence between 0.0 and 1.0. If the runtime encounters an Uncertain value in a conditional expression (if) or arithmetic operation (+) and the confidence falls below the system's StrictnessThreshold, the VM triggers an immediate Execution Trap. This prevents agents from branching on low-confidence hallucinations — the kind of silent corruption that is nearly impossible to debug in production.


Error Model

Turn does not use try/catch exception handling. This is a deliberate design decision, not an omission.

IMPORTANT

Hallucinations and stochastic failures from LLM inference are expected outcomes, not exceptional errors. Hiding them behind exception handlers obscures control flow, encourages developers to ignore failure cases, and leads to silent data corruption. Turn treats every fallible operation as a value that must be explicitly matched.

The error model is built on two monadic types:

  • Result<T, E> is returned by infer and any operation that can fail in a recoverable way. The agent must pattern-match against Ok(value) or Err(error). If a Result::Err is not handled and the value is used, the VM propagates it as a process exit signal to any linked supervisors.

  • Option<T> is returned by recall(key) when the requested key may not exist in memory. It evaluates to Some(value) when the key is present and None when it is absent. This forces the developer to handle the missing-data case explicitly, rather than discovering null at an unexpected point later in execution.

Process-level failures (unhandled errors, token budget exhaustion, capability violations) propagate as exit signals through the supervision tree, following Erlang's "let it crash" philosophy. Errors are isolated to individual processes and handled structurally by supervisors — not by deep stack unwinding.