Runnable language cookbook
Find the idea. Run the proof.
Short, source-backed recipes for the language as it exists today — from a two-line binding to effects, web servers and native builds.
Start from an outcome
Use a short route when you want a working mental model without reading the entire catalog.
Learn the core language
Bindings, operators, control flow and functions.
Start with the essentialsModel reliable data
Structs, stored-field accessors, enums and Result.
Start with the essentialsBuild services
HTTP routes, JSON, database queries and workers.
Start with the essentialsExplore modern Zolo
Comptime, reflection, state machines and effects.
Start with the essentialsThe complete recipe library
Open only the act you need. Search scans titles, descriptions, chapters and syntax across the whole library.
01 Act 1 Fundamentals
Hello & Comments
2 recipes
Primitives & Numbers
5 recipes
- Integers & Floats int and float, arithmetic, and int → float coercion.
- Number Bases Hex, binary, octal literals and the _ digit separator.
- Numeric Types Fixed-width aliases (u8, i32, f32, usize) as annotations and suffixes.
- Booleans true, false, and the logical operators.
- Nil & Optional nil, the absence of a value, and optional types.
Variables and Bindings
7 recipes
- Overview How Zolo names values: a tour of the binding forms.
- Bindings: let, let mut and var Creating immutable bindings with let, mutable ones with let mut, and the var shorthand.
- Constants and Override const for fixed compile-time values; override for constants that can be replaced at load time.
- Type Annotations and Optionals Automatic inference vs explicit annotation; the T? type for values that may be nil.
- Shadowing and Scope Redeclaring a name with let (shadowing) and how lexical scope defines the lifetime of a binding.
- Destructuring Extracting multiple values from arrays, structs, and enums in a single pattern.
- Storage Classes and Discard var<lazy>, var<persistent>, var<atomic>: initialization control and lifecycle; and _ to discard values.
Operators
6 recipes
- Arithmetic Arithmetic operators: +, -, *, /, %, **, unary -, floor division ~/ and compound assignment.
- Comparison and Logic Relational operators (==, !=, <, <=, >, >=) and logical operators (&&, ||, !) with short-circuit evaluation.
- Ranges and Spread Range operators (.. exclusive, ..= inclusive), array slicing and the spread ... in literals.
- Pipeline Pipeline operators |> (data-first chaining) and &. (side-effect tap without breaking the flow).
- Nil Safety Operators ?. (safe navigation), ?? (nil coalescing) and ? (nil propagation).
- Fallible Chaining The ?> operator: chain calls that may fail, short-circuiting on error.
Control Flow
4 recipes
- if / else Conditionals as a statement and as an expression, if-let and let-else.
- Loops while, while-let, value-producing loops, for over ranges and collections, labelled break/continue.
- Match Pattern matching: literals, or, ranges, guards, structs, enums and nesting.
- defer Schedule cleanup for scope exit, in LIFO order.
02 Act 2 Functions & Logic
Functions
6 recipes
- Named Functions Declaration with fn, explicit or inferred types, and local helper functions.
- Lambdas and Closures Anonymous functions with |args| expr and lexical scope captures.
- Flexible Parameters Default values with p: T = expr and varargs with args: ...T.
- Multiple Returns and Recursion Returning multiple values via [T] with destructuring, and functions that call themselves.
- Higher-Order Functions Functions as argument or return, composition, map/filter/reduce, and closures with mutable state.
- Generators and Coroutines fn* and yield for lazy sequences; async fn for cooperative tasks.
Pattern Matching
6 recipes
- Basic Patterns: Literals, Wildcard and Binding The three fundamental building blocks of every pattern: match by exact value, ignore with `_`, or capture the value into a name.
- Or Patterns, Ranges and Guards Group alternatives with `|`, classify numeric intervals with `..=`, and refine patterns with extra `if` conditions.
- Binding with @ The `@` operator captures the value that satisfies a sub-pattern, combining verification and binding in a single step.
- Destructuring: Tuples, Arrays, Structs and Enums Extract fields and elements from composite structures directly in the pattern — in `let`, `match` and `for`.
- Nested Patterns Combine patterns inside patterns to extract data from deep structures in a single match arm.
- Patterns in Statements: if let, while let, let else and match-expression Beyond `match`, patterns appear in `if let`, `while let`, `let else` and as expressions that return a value.
Error Handling
7 recipes
- Result: success or error as a value Create and inspect Result.Ok / Result.Err; use is_ok, unwrap, unwrap_or and exhaustive match.
- The ? Operator Propagate Result and Option automatically with ? — no nested match boilerplate.
- Result Combinators Transform and chain results with map, map_err, and_then and or_else without unwrapping.
- Optionals T?, nil, ??, ?. and if let — represent absent values without an error.
- panic, try/catch and catch_panic Signal broken invariants with panic; capture them with try/catch/finally and catch_panic.
- defer, defer_ok and defer_err Guarantee resource cleanup on scope exit; filter by exit path with defer_ok/defer_err.
- Guards and early return Validate preconditions at the top of a function and simplify the happy path with ? in pipelines.
03 Act 3 Data & Types
Data Structures
11 recipes
- Arrays Ordered collection with indexing, slicing, spread, and functional operations.
- Maps and Sets Key/value maps with the `#{}` literal and sets for membership without duplicates.
- Tuples Positional grouping with destructuring — multiple return values and pairs.
- Structs Records with named fields, nesting, mutation, and methods via `impl`.
- Enums Unit variants, variants with positional data, named-field variants, and generic enums.
- Newtypes Opaque wrappers to distinguish types that share the same physical format in the domain.
- Type Aliases type X = T — a transparent name for an existing type.
- When to Use Each Type Decision guide: array vs set vs map vs struct vs enum vs newtype.
- Memory Layout `@repr`, `@align`, and `@size` for layout control in FFI and GPU.
- Field Embedding with `using` Promote an embedded struct''s fields into the outer struct''s dot-access with `using`.
- Custom Iterators Make any type pluggable into `for x in` by implementing Iterator<T> or IntoIterator<T>.
Strings
8 recipes
- Literals and Escapes Double quotes, escape sequences (\n \t \" \\) and the char type.
- Concatenation and Interpolation The + operator for joining strings and the {expr} syntax for embedding values.
- Format Specifiers Float precision (:.Nf), zero-padding (:0Nd) and hexadecimal (:#x) in interpolation.
- Case and Trim .upper, .lower, .trim, .trim_start and .trim_end for normalizing text.
- Search and Test .contains, .starts_with and .ends_with to check substrings without regex.
- Split and Replace .split(sep) splits into an array; .replace(old, new) substitutes all occurrences.
- Length and Character Iteration .len() returns bytes; .chars() returns a string array for iterating character by character.
- String Module String.upper, String.sub, String.reverse — the functional style equivalent to the methods.
Iterators and Pipes
6 recipes
- Pipe Operator `|>` chains calls data-first, making transformations readable from left to right.
- Tap Operator `&.` runs a side effect and returns the original value — the pipeline "spy".
- Iter Sources and Transformations `Iter::range`, `Iter::from`, `map` and `filter` build and transform sequences lazily.
- Reduction and Slicing `fold` collapses a sequence into a value; `take` and `skip` limit and paginate iterators.
- Combining Iterators `zip` pairs two iterators; `chain` concatenates them; `collect` and `each` are the terminal consumers.
- Generators and Infinite Sequences `fn*` + `yield` create lazy on-demand sequences; infinite ranges (`0..`) compose with `take` in pipelines.
04 Act 4 Abstraction
Object-Oriented Programming
7 recipes
- impl Blocks and Instance Methods How to group methods on a type with impl, use self, and mutate fields directly.
- Associated Functions and Multiple impl Blocks Constructors and utilities without self, called via Type::name(), and how to split methods across separate impl blocks.
- Traits Define interfaces with trait, implement them on concrete types with impl Trait for Type, use default methods, and combine multiple traits.
- Generics Parametrize functions, structs, and enums with <T> to write code that works with any type.
- Trait Bounds Constrain a generic with inline bounds or a where clause so the body can call trait methods on it.
- Implementing Std Traits Implement core::cmp::Ord on your type so it works with comparison operators and generic Ord bounds.
- Operator Overloading, to_string, and Chaining Bind operators to methods via name convention or @op, control text representation with to_string, and build fluent APIs with method chaining.
05 Act 5 Metaprogramming
Decorators
6 recipes
- Result Caching Automatic memoization with @memoize and expiring cache with @cached(ttl).
- Performance and Diagnostics Automatic instrumentation with @benchmark, @log, and fault tolerance with @retry.
- Structs: Derive and Validation Automatic generation of Eq, Clone, and Debug with @derive, and field validation with @validate.
- Tests and Benchmarks with the Runner Functions automatically discovered by the runner: @test for unit tests and @bench for performance measurement.
- HTTP Routes and API Quality Declarative routes with @get/@post, deprecated API with @deprecated, mandatory return value with @must_use, and lint control with @diagnostic.
- Composition and Custom Decorators Stacking decorators, @const compile-time parameters, and user-defined mixins with super().
Macros
5 recipes
- Definition and Invocation How to declare a macro with `macro name(p) { ... }` and call it with `name!(arg)`.
- stringify! and assert! Inspect source code at expansion time and create rich assertions with `stringify!`.
- Hygiene, Recursion, and Block Arguments Internal variables do not leak to the caller; macros can call themselves; `{}` blocks as arguments.
- Logging DSL Small macros compose a mini logging language with standardized levels.
- macro_rules! Rust-style macros with multiple arms, `$(...),*` repetition, and capture kinds.
Compile-Time Evaluation
5 recipes
- comptime block comptime { ... } evaluates a block inline in the compiler and replaces the result with a literal.
- comptime functions Declare reusable helpers with @comptime fn and invoke with comptime f(x) — the call-site becomes a literal.
- Recursion, loops, and tables Recursive comptime functions, for loops inside comptime blocks, and compile-time generation of literal arrays.
- stdlib and file embedding String methods, math.* and comptime fs.read() work in a comptime context — normalize text and embed files as literals.
- const_assert Fail the build if a compile-time invariant is not satisfied — zero cost in production.
Reflection & Metaprogramming
14 recipes
- Compile-Time Field Names Read a type's field names and type kinds at compile time using typeinfo(T).
- Runtime Reflection Opt a struct into runtime type metadata with @reflect, then query it via typeinfo(value).
- Decorators as Inert Data Field decorators are surfaced through typeinfo so comptime routines can read them as data.
- Compile-Time Serialization Template Walk typeinfo fields at compile time to generate a JSON-shape template as a constant string.
- ORM: Generate CREATE TABLE Derive a SQL CREATE TABLE statement from a struct at compile time using typeinfo and field decorators.
- Derive Validation Rules Use typeinfo on a schema to generate a human-readable list of field constraints at compile time.
- UI Form Generation Derive a form spec from a struct: decorators supply labels, type.kind selects the input widget.
- OpenAPI / JSON Schema Generation Generate an OpenAPI properties fragment from a struct at compile time by mapping type.kind to JSON Schema types.
- Generic Derive Function Write one @comptime fn that accepts typeinfo and works for any struct or enum — the substrate for derive macros.
- Runtime Debug Introspection With @reflect, a generic debug dumper can report any value's type shape at runtime — no per-type code needed.
- Built-In Derives Use @derive(Debug, Eq, Clone) to auto-generate standard trait implementations for a struct.
- Custom Derive Register your own derive with @derive_for: a comptime fn receives typeinfo and returns Zolo source to splice.
- Derive: SQL Column List A derive that uses closures and list.join to build a SQL column list from typeinfo fields.
- Derive: Full DB Table DDL A derive that builds a complete CREATE TABLE statement, mapping field types and reference relations to SQL.
Schemas
4 recipes
- Default Values Declare fields with `= value` and get a ready-made instance with `Schema.default()`.
- Field Introspection `Schema.fields()` returns the field names in declaration order, enabling generic rendering and migrations.
- Parse and Serialize `Schema.parse(map)` validates input returning a `Result`; `instance.to_map()` converts it back to a map.
- `where` Constraints Add domain invariants to fields with `where |v| <bool>` — checked automatically during `parse`.
06 Act 6 Project Structure
Modules
6 recipes
- mod and use Register a module with `mod` and bring names into scope with `use`.
- Visibility and pub `pub` exports an item; without `pub` it is private to the module.
- Import styles Qualified, list, or multiple modules: when to use each style.
- Native plugins and stdlib `use plugin` for native plugins; qualified `std::` paths need no `use`.
- Inline modules and granular visibility Modules declared inside a file, `use ... as`, and `pub(mod)` / `pub(crate)` modifiers.
- Multi-file project How `mod` and `use` work in a program with multiple files.
Documentation
4 recipes
- Comments Line comments (//), block (/* */), nesting, and TODO/FIXME/NOTE conventions.
- Doc Comments Doc comments /// and /** */ on functions, structs, enums, and traits — shown in editor hovers.
- Doc Tags Tags @param, @returns, @throws, @example, @see, @since, and @deprecated in doc comments.
- Self-Documenting Code Descriptive names, explicit types, aliases, named constants, and structs/enums as living documentation.
Module Directives
2 recipes
Lifecycle Hooks
3 recipes
- Shutdown Hook Register cleanup code with `on shutdown` — runs on normal exit or via `process.exit`.
- Multiple Hooks Composing `on shutdown`, `on panic`, and `on signal` in the same program; firing order and LIFO.
- Panic and Signals Intercept fatal errors with `on panic` and OS signals with `on signal`.
07 Act 7 Concurrency & Reactivity
Temporal Expressions
6 recipes
- Duration Literals Unit suffixes on numbers: ns, us, ms, s, min, h, d, w — all become i64 in milliseconds.
- Duration Arithmetic Addition, subtraction, multiplication and division between durations; direct comparisons.
- Unit Casting Extract clock components with `as h`, `as min`, `as s`, `as ms` to format durations.
- Sleep Pause execution with `sleep <dur>` or `sleep(<dur>)` — cooperative, yields control to the scheduler.
- Scheduling: every, after, and timeout Periodic loop with `every`, one-shot firing with `after`, and deadline cancellation with `timeout`.
- Practical Patterns Heartbeat, TTL, exponential backoff, alert bands, and warm-up combined with a periodic loop.
Concurrency
6 recipes
- Coroutines and Generators The core concurrency primitive in Zolo: coroutine.create/resume/yield and generator functions fn*.
- Async / Await and Fetch async fn, await, Promise.all/race/any and the fetch API for concurrent HTTP requests.
- Spawn, Timing, and Cancellation spawn launches cooperative tasks; every/after schedule work over time; cancellation uses shared flags.
- Pipelines and State Machines Generators chained as pull-based stages, and state machines expressed as sequences of yield.
- Channels CSP-style message passing: channel(N), send/recv, for-in, bounded channels, and backpressure.
- Structured Concurrency, Select, and Worker Pool scope waits for all children; select waits on multiple channels; worker pool implements fan-out + fan-in.
Signals
5 recipes
- Basic Signal Create a signal with `signal()`, read with `.get()` and write with `.set()`.
- Effects The `effect` runs immediately on creation and re-runs every time a tracked signal changes.
- Computed Values The `computed` creates a memoized derived signal: it recalculates only when a dependency changes.
- Untracked Reads `signal_untrack`, `peek` and `modify`: read a signal without creating a dependency and update functionally.
- Batch, Dispose and Full Demo Coalesce multiple writes with `signal_batch`, cancel effects with `.dispose()` and see the three primitives composed.
State Machines
4 recipes
- Declaration and Transitions How to declare states, set the initial state, and fire events with `.send`.
- Transition Actions Code blocks that execute automatically when a transition occurs.
- Querying and Observers `.can_send` checks if an event is applicable; `.on_transition` registers global observers.
- Introspection `.transitions()` exposes the full transition table for tooling, diagrams, and tests.
Algebraic Effects
6 recipes
- Fundamentals Declare an effect, fire operations with perform, and install a handler with handle … with.
- Multiple Effects with E1 + E2 combines effects in the signature; nested handlers and transitive effects complete the picture.
- resume and abort resume(v) returns control to perform with a value; abort(v) discards the continuation and exits the handle.
- Handlers as Values handler { … } creates a first-class value; compose, override, record, and panic_unhandled layer on top of it.
- Functional Patterns Reader, State, and Writer implemented as effects; a real-world case with Db + Fs + Log + Metric and in-memory mocks in @test.
- Advanced Types multi fn, generic effects State<T>, row polymorphism, effect aliases, and std::effect combinators.
08 Act 8 Standard Library
Standard Library
26 recipes
- Math (std::math) Math functions, constants, exact decimal arithmetic and approximate float comparison.
- Strings (std::string) Trimming, splitting, replacing, searching, case conversion, character iteration and formatting.
- Arrays (std::array) Mutation, transformation, filtering, aggregation, search and flattening of arrays.
- Vectors (std::vec) 2D/3D/4D vectors: constructors, arithmetic, dot and cross product, length, normalisation and rgba swizzle.
- Maps (std::map) Creation, insertion, reading, deletion, iteration and the difference between #{} literals and Map::new().
- Sets (std::set) Uniqueness, membership, removal, set operations (union and intersection) and conversion with arrays.
- Iterators (std::Iter) Lazy sequences: range, map, filter, fold, take, skip, zip, collect and each.
- Result (std::Result) Error handling without exceptions: Ok, Err, unwrap, map, and_then and the ? operator.
- JSON (std::json) Serialising and deserialising JSON: encode, decode, error handling, json"..." literal, path and schema interop.
- YAML (std::yaml) Parsing and serialising YAML: hierarchical configs, lists and round-trip.
- TOML (std::toml) Parsing and serialising TOML: sections, explicit types and round-trip.
- CSV (std::csv) Parsing and serialising CSV: rows, headers, quote escaping and round-trip.
- Regular Expressions (std::regex) Validate, extract, replace and split strings with regular expressions.
- Date and Time (std::datetime) Get the current instant, format and parse dates, and perform calendar arithmetic with std::datetime.
- Paths (std::path) Manipulate paths portably: join components, extract parts, normalize, and resolve relative paths.
- File System (std::fs) Read, write, delete files, list directories, and work with temporary files using std::fs.
- Environment Variables (std::env) Read, set, and remove environment variables; get system information with std::env.
- Process (std::process) Access arguments, working directory, run external commands, and inspect the current process with std::process.
- I/O Reactor (std::io_runtime) I/O-reactor-based timers: one-shot sleep, periodic timers with cancellation.
- HTTP Client (std::http) Make GET, POST and other requests via std::http.client — custom headers, JSON body and error handling.
- URLs (std::url) Parsing, percent-encoding and query string building with std::url.
- Cryptography (std::crypto) Unique ID generation and cryptographically secure randomness with std::crypto.
- Hashes (std::hash) SHA-256, SHA-512, MD5, CRC32 and HMAC for content integrity and message authentication with std::hash.
- Base64, Hex and Base32 (std::base64) Standard, URL-safe, Hex and Base32 encoding and decoding for representing binary data as text.
- Log (std::log) Structured logging by severity level, verbosity control and custom formatting with std::log.
- Statistics (std::stats) Central tendency, dispersion, percentiles, correlation and linear regression with std::stats.
09 Act 9 Platform & Apps
HTTP Server
5 recipes
- HTTP Client — GET Making GET requests with optional headers and reading the response object.
- HTTP Client — POST JSON and fetch Sending data with http.post and using http.fetch for arbitrary methods and timeout.
- Server — Router and Decorators Creating an HTTP server with http.router() via pipes or with @get/@post decorators.
- Route Parameters and Middleware Reading :id and query string via req.params/req.query; adding middlewares with http.middleware.
- Responses and Workers http.response, http.html and http.redirect for status control; http.workers for parallelism.
Database
7 recipes
- Connection and Ping Open a connection with Database.open, verify with ping, and close with defer.
- DDL and Insertion Create tables with db.execute and insert rows, counting the affected ones.
- Row Querying db.query returns a list of maps {column: value} that can be iterated with for.
- Parameterized Queries Use ? + bindings array to safely pass external values.
- Transactions db.transaction guarantees atomicity: automatic commit on return, automatic rollback on error.
- sql"…" — Safe Template and Scalar The sql"..." literal auto-parameterizes interpolations and exposes :query, :execute, and :scalar methods.
- SQL Injection Protection Interpolations in sql"..." are always bound parameters — SQL metacharacters in the value are literals, never executed.
CLI and Tooling
9 recipes
- Process Arguments Read the command line with `process.argv()` and isolate user arguments.
- Environment Variables and Platform Read, set, and remove environment variables; detect OS, architecture, and home directory.
- Process Lifecycle Exit with `process.exit`, register `on shutdown` hooks, catch panics, and handle OS signals.
- Doctor Command Diagnostic pattern: aggregate environment checks and exit with a non-zero code when something fails.
- @cli Builder Declarative parsing with `@cli` + `@arg`: flags, positionals, automatic `--help`, and subcommands.
- Command Literals and Safety Build lazy commands with sh"…", interpolate argv safely, and handle typed process errors.
- Process Effects and Pipelines Mock process execution, pipe real processes, and transform structured process data.
- Streaming and Executable Scripts Consume process output incrementally and run .zolo files with a Unix shebang.
- Parallel Commands and Terminal UI Run independent commands concurrently and add accessible ANSI styling to interactive CLIs.
Hot Reload
6 recipes
- Basic Reload The "hello world" of zolo dev: edit a module, save it, and see the new version in action without restarting the VM.
- State Preservation pub let with a stable runtime type survives the swap — the accumulated value continues; only the new literal initializer is discarded.
- Reload Lifecycle Hooks Three extension points in the swap pipeline: __on_reload for notification, #[hot_dispose] to capture state before, and #[hot_accept] to restore it after.
- Asset Reload HMR for data files: edit config.json, shaders, or CSVs and the __on_asset_reload hook reacts without restarting the VM.
- Undo/Redo and Advanced Cases Time-travel through swap history via :undo / :redo / :history, plus transparent reload in tight loops without yield and closure references captured outside the live-binding.
- Render Loop and HTTP Server Hot reload in a wgpu render loop with 1000 cubes and in a running HTTP server — without losing the listener or GPU state.
10 Act 10 Build, Test & Ship
Testing
4 recipes
- Matchers with expect() The expect() library and its matchers: equality, length, membership, prefix, and negation.
- Suites with @suite Group tests in modules annotated with @suite, including nested suites.
- Test Attributes Control execution with skip, should_throw, only, and tag in the @test and @suite decorators.
- Lifecycle Hooks Run code before and after each test or the entire suite with @before_each, @after_each, @before_all, and @after_all.
Compilation
4 recipes
- run vs build Interpreted VM (`zolo run`) and native backend (`zolo build`): when to use each one and what changes between them.
- --emit Flags Stop the compilation pipeline early: `--emit ir` prints the ZoloIR; `--emit obj` writes an object file without linking.
- Release Build The `--release` flag enables Cranelift optimisations to produce a faster binary, at the cost of a slower build.
- compile and bundle `zolo compile` shows the Lua generated for the VM; `zolo bundle` groups the entry point and its modules into a single portable Lua file.
WebAssembly
4 recipes
- Emit Wasm Compile a Zolo program to `.wasm` with `zolo build --emit wasm`; understand VM-embedded mode and the default host-shim ABI.
- Host Profiles Select the runtime profile with `--host wasi|browser` and enable the experimental AOT backend with `--aot`.
- Export Functions Use `@export` to expose Zolo functions to JavaScript/TypeScript via AOT wasm with `--host browser`.
- Arrays in Wasm Use arrays in AOT functions and export functions that accept or return `[int]`, `[bool]`, and `[str]` to JavaScript.
Distribution
3 recipes
- .zar and .zex Files Package code as a reusable library (`.zar`) or portable executable (`.zex`) with `zolo build --emit`.
- Standalone Binary Embed the runtime into the `.zex` with `--standalone` to distribute without requiring `zolo` to be installed.
- GUI and Windowed Distribute desktop apps without a console window using `--windowed` / `--gui`; run ready-made files with `zolo run`.
OS Integration
1 recipes