A language for building microservices and enterprise software, with dependency injection, function intent, and refined types as first-class citizens. Compiled to native binaries.
Ideas that usually live in frameworks and conventions are, in Ξ, features of the language itself.
Constraints live in the type. Values are checked at construction, so a partially-valid instance can never exist.
Number where value >= 0
Every function declares its kind: mapper, predicate, consumer, producer and more. Purity and effects are part of the signature, and the compiler enforces them.
mapper · predicate · consumer
Declare deps { } and the compiler wires it. No container, no registration, no reflection.
One name, many bodies: the first where guard that holds wins. It is exactly how std/web routing works.
where res.status == 200
Business rules as first-class DxT tables, alongside atoms, state machines, interrupts and pub/sub events.
DxT · atoms · machines ↓T! result types, ok/err, and ? propagation. Failures are values you handle, not surprises.
let row = load(id)?
async spawns a worker and returns a Future immediately. await all joins them, in order.
await all jobs
Absence is typed. Optionals (T?) unwrap with if let; empty gives the zero value. null does not exist.
if let row = find(7) { … }
Algebraic types with payload-binding match. Lowered to plain tagged unions.
match s { Circle c -> … }
Resumable conditions. A function signals and suspends while the caller decides whether to resume or abandon it.
Built-in pub/sub. Producers publish a DTO; listeners receive the typed value. No JSON inside the process.
Compiles to a standalone binary, or to WebAssembly with --target wasm. No VM, no garbage collector.
xc app.xi → ./build/app
Every serious codebase ends up bolting on an IoC framework with annotations and a runtime registry. In Ξ the compiler does the injection: you declare what you need and the wiring is derived from your code.
A class lists what it needs in a deps { } block. It never news up its own collaborators, so constructor plumbing disappears from the codebase.
Implementations are discovered and wired automatically at compile time. There is no container to configure and no reflection involved. A missing dependency is a build error rather than a runtime surprise.
The entry takes dependencies as parameters. Classes, listeners and even decision tables declare deps. Lifetimes are explicit: singleton or transient.
bind is the override, not the ruleYou only write bind to choose between implementations or swap in a test double. Zero bindings is the normal case.
Rules engines, state stores and state machines are language constructs in Ξ. All three are ordinary values, and all three are injectable.
A decision is a function kind whose body is a set of when → result arms, read top to bottom until the first match wins. The rule set your product owner writes on a whiteboard is the code.
when <cond> => <result> arms, or a tabular grid of in columns and an out column
hit first the first matching arm wins
An atom holds an immutable state that can only change through transition reducers, so every change is named and typed.
.current; the state is immutable and there are no setters
transition reducers take the state and return a new one; call them with just the extra args
.undo() / .canUndo() give you history for free
A machine declares named states, machine-wide data, and transitions with parameters. Machines are immutable: every transition returns a new value.
where guards and update clauses on every transition
.can(...)
IllegalTransition, a resumable interrupt you can recover from
A function signals a condition and suspends. The enclosing try/catch decides what happens next. Where an exception unwinds the stack, an interrupt lets the caller repair the situation and continue.
interrupt declares a typed condition with a payload
recover runs the restart and resumes at the signal point
skip abandons the suspended computation instead
Producers publish(topic, dto); a listener receives the typed value with zero serialization in process. Bind a transport to cross the network; producers and listeners never change.
listener kind subscribes with on "topic"; each delivery resolves fresh deps
Events.run() or Events.runAsync()
PublisherService / ConsumerService to go external
A typed web framework, a test runner, configuration and C interop ship with the toolchain. Building a service needs no packages.
Implement WebRequestHandler and match requests with web.route in where guards. Params and bodies decode into your types; responses serialize themselves. HTTPS and HTTP/2 are opt-in flags.
test blocks are excluded from normal builds and run with xt. Tests get dependencies injected, and module Test bindings swap in test doubles without a mocking library.
Config is an interface bound to a file: bind AppConfig -> readConfig("app.yaml"). YAML, JSON or XML, with hot-reload included.
Port a C library by declaring it: an extern "C" block plus a link directive. The signatures are the binding.
List, Map, Set, Stack, Queue, SortedQueue are built-in generics. No imports needed.
math · text · json · yaml · xml · crypto · fs · net · http · thread · process · time
xc app.xicompile to a native binaryxirun tool + interactive REPLxt calc_test.xirun the testsxi installfetch module dependenciesxi packpackage a library for othersloadtest --bench app.xiload & perf testingxc --target wasmcompile to WebAssemblyxi updateself-update the toolchaineXstream is a music-streaming service built in Ξ: microservices behind an API gateway, JWT auth, a React front end, Docker deployment.
code-by-sia/eXstream ↗On macOS (Apple Silicon & Intel) and Linux. You just need a C compiler on your PATH.
Or grab a prebuilt tarball from the releases page and put its bin/ on your PATH.
You get xc, the compiler, and xi, the run tool and REPL.
Save a file with the .xi extension. Every program has an entry and a module.
One command compiles to a native binary and runs it.
A simulated editor. Pick an example, edit it, and run to see the compiler output.