Introduction

What XS is, what ships in the binary, and where to start reading.

What it is

XS is a programming language. Anywhere, anytime, by anyone.

The same source compiles to native machine code, JavaScript, or WebAssembly, and runs unchanged on Linux, macOS, Windows, WASI, iOS, Android, ESP32, and Raspberry Pi. Types are optional. Write a script the way you would write a script; add types when the program grows large enough that they pay for themselves.

scratch.xs

Add annotations when something benefits from enforcement. The type checker only activates on annotated code; everything else passes through.

scratch.xs

What ships in the binary

One statically-linked binary, around 2.9 MB on Linux x86-64. It contains the compiler, the language server, the debugger, the formatter, the linter, the test runner, the profiler, and the package manager. There is nothing else to install. HTTPS uses an embedded BearSSL; HTTP uses raw POSIX sockets. The binary builds with gcc or clang and GNU make from a clean checkout.

What it does

Pattern matching with literal, range, struct, and enum patterns; guards on any arm; the semantic analyser checks exhaustiveness.

scratch.xs

Algebraic effects: declare a side requirement as a named effect, let the caller decide how it is handled. The handler can resume back to the perform site with a value.

scratch.xs

Concurrency primitives: spawn for real OS threads, channels for message passing, actors for encapsulated state, nurseries for structured concurrency, async / await for I/O. The bytecode VM holds a global lock during its dispatch loop, so two pure-compute threads take turns rather than running in parallel; the lock releases around sleep, I/O, and channel receive, so spawn-and-block parallelises the way you would expect. Same model as CPython.

Backends: a tree-walk interpreter for the REPL and AST-level plugin hooks, a bytecode VM for the default path, a register-allocating JIT for x86-64 and aarch64, plus transpilers to C, JavaScript, and WebAssembly. The interp and the VM are diff'd against each other on every commit; a divergence fails the test even if each backend passes on its own.

Next steps

The guide reads top to bottom: each chapter builds on the last.