Examples catalog

Every runnable (or intentionally non-runnable) program under examples/. Run from the repository root unless noted otherwise:

cargo run -- --root ../coil-stdlib/src examples/<file>.hy

The examples import the userland stdlib (io::sync, string, …), so every run needs --root pointing at a coil-stdlib checkout (here a sibling ../coil-stdlib). The Run rows below omit it for brevity. The default run compiles in memory, so there is no out.hyc to delete after editing source.

Note: The CLI uses multi-file discovery (Pipeline::compile_src_from_file) over its --root search roots, so use / mod examples such as modules.hy work from cargo run with --root examples/src. coil reads no coil.toml or coil.lock; the workspace coil.toml is for spool, which turns it into flags. FFI examples need libffi and sometimes a built shared library (libsum.so / libsum.dylib / sum.dll).


Basics#

Core syntax: functions, let, arithmetic, control flow, and I/O.

examples/print_literal.hy#

Demonstrates: Literal string output with io::write_all.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    write_all(stdout(), to_bytes("hello"));
}
Runcargo run -- examples/print_literal.hy
Outputhello

examples/format_literal.hy#

Demonstrates: Formatted output with string::format and io::write_all.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    write_all(stdout(), to_bytes(format("%i", 42)));
}
Runcargo run -- examples/format_literal.hy
Output42

examples/string_fmt.hy#

Demonstrates: String concatenation with + and the format expression returning a string.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    let a = "hello";
    let b = "world";
    write_all(stdout(), to_bytes(format("%s", a + " " + b)));
    let s = format("%i-%s", 42, "x");
    write_all(stdout(), to_bytes(format("%s", s)));
}
Runcargo run -- examples/string_fmt.hy
Outputhello world42-x

examples/show_tuple.hy#

Demonstrates: %v structural Show for tuples and anonymous records.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    write_all(stdout(), to_bytes(format("%v", (1, 2))));
    write_all(stdout(), to_bytes(format("%v", { a: 3, b: 4 })));
}
Runcargo run -- examples/show_tuple.hy
Output(1, 2){ a: 3, b: 4 }

examples/let_test.hy#

Demonstrates: let bindings, reading locals, and reassignment (x = 20;).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    let x = 5;
    write_all(stdout(), to_bytes(format("%i", x)));
    let y = 10;
    write_all(stdout(), to_bytes(format("%i", y)));
    x = 20;
    write_all(stdout(), to_bytes(format("%i", x)));
}
Runcargo run -- examples/let_test.hy
Output51020

examples/defer.hy#

Demonstrates: defer blocks that run on function exit (fall-through or early return), including LIFO order when multiple defers are registered, plus defer use (n) to capture an outer local.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn with_cleanup() {
    defer { write_all(stdout(), to_bytes("leave")); }
    write_all(stdout(), to_bytes("enter"));
}

fn lifo() {
    defer { write_all(stdout(), to_bytes("1")); }
    defer { write_all(stdout(), to_bytes("2")); }
    write_all(stdout(), to_bytes("0"));
}

fn early_return(int n) -> int {
    defer { write_all(stdout(), to_bytes("d")); }
    if n == 0 {
        return 99;
    }
    write_all(stdout(), to_bytes("ok"));
    return n;
}

fn capture_n(int n) -> int {
    defer use (n) { write_all(stdout(), to_bytes(format("%i", n))); }
    return n;
}

fn main() {
    with_cleanup();
    write_all(stdout(), to_bytes(","));
    lifo();
    write_all(stdout(), to_bytes(","));
    write_all(stdout(), to_bytes(format("%i", early_return(7))));
    write_all(stdout(), to_bytes(","));
    write_all(stdout(), to_bytes(format("%i", early_return(0))));
    write_all(stdout(), to_bytes(","));
    write_all(stdout(), to_bytes(format("%i", capture_n(5))));
}
Runcargo run -- examples/defer.hy
Outputenterleave,021,okd7,d99,55

examples/named_args.hy#

Demonstrates: Named call-site arguments (name: value), including a positional prefix followed by named args.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn greet(string name, int age) {
    write_all(stdout(), to_bytes(format("%s", name)));
    write_all(stdout(), to_bytes(format("%i", age)));
}

fn main() {
    greet(name: "Ada", age: 36);
    greet("Grace", age: 40);
}
Runcargo run -- examples/named_args.hy
OutputAda36Grace40

examples/variadic.hy#

Demonstrates: Trailing rest parameters (T... name) packing into a Vec<T>, including an empty rest and named fixed args followed by positional rest.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn sum(int... xs) -> int { /* len + loop */ }
fn greet(string name, string... extras) -> string { /* concat */ }

fn main() {
    write_all(stdout(), to_bytes(format("%i", sum(1, 2, 3))));           // 6
    write_all(stdout(), to_bytes(format("%i", sum())));                  // 0
    write_all(stdout(), to_bytes(format("%s", greet(name: "Hi", "!", "?")))); // Hi!?
}
Runcargo run -- examples/variadic.hy
Output60Hi!?

examples/const.hy#

Demonstrates: Immutable const bindings (reassignment is rejected by the typechecker).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    const answer = 42;
    write_all(stdout(), to_bytes(format("%i", answer)));
    const greeting = "hi";
    write_all(stdout(), to_bytes(format("%s", greeting)));
}
Runcargo run -- examples/const.hy
Output42hi

examples/loop_break.hy#

Demonstrates: while with continue and break (sum 0+1+2+4+5+6 = 18).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    let sum = 0;
    let i = 0;
    while i < 10 {
        if i == 3 { i = i + 1; continue; }
        if i == 7 { break; }
        sum = sum + i;
        i = i + 1;
    }
    write_all(stdout(), to_bytes(format("%i", sum)));
}
Runcargo run -- examples/loop_break.hy
Output18

examples/fizbuz.hy#

Demonstrates: if conditions, modulo, and independent stdout writes (FizzBuzz-style, without newlines between numbers).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn fizbuz(int n) {
    if (n % 3) == 0 {
        write_all(stdout(), to_bytes("FIZ"));
    }
    if (n % 5) == 0 {
        write_all(stdout(), to_bytes("BUZ"));
    }
}

fn main() {
    fizbuz(1);
    fizbuz(2);
    // ... through fizbuz(15)
}
Runcargo run -- examples/fizbuz.hy
OutputFIZBUZFIZFIZBUZFIZFIZBUZ

examples/fib.hy#

Demonstrates: Recursive functions, if, and integer arithmetic (smoke / docs).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn fib(int n) -> int {
    if n <= 2 {
        return 1;
    }
    return fib(n - 1) + fib(n - 2);
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", fib(32))));
}
Runcargo run -- examples/fib.hy
Output2178309

Cross-language CPU baselines (mandelbrot / tak / nsieve / binary trees / fib) live under examples/perf/ with matching benchmarks/*.{lua,js} ports. For timing, prefer coil compile … -o x.hyc then coil run x.hyc (see ./scripts/poop_baseline.sh). Compile perf/fib.hy with COIL_AUTO_PAR=0 so the naive recursion stays sequential like the Lua/Node ports.


examples/perf/mandelbrot.hy#

Demonstrates: Nested loops + float arithmetic; fair cross-lang checksum bench.

Runcargo run --release -- examples/perf/mandelbrot.hy
Output625885
Portsbenchmarks/mandelbrot.lua, benchmarks/mandelbrot.js

examples/perf/tak.hy#

Demonstrates: Deep Takeuchi recursion (no auto-par binary shape).

Runcargo run --release -- examples/perf/tak.hy
Output7
Portsbenchmarks/tak.lua, benchmarks/tak.js

examples/perf/fib.hy#

Demonstrates: Plain naive fib(32) recursion (math/dispatch baseline).

RunCOIL_AUTO_PAR=0 cargo run --release -- examples/perf/fib.hy
Output2178309
Portsbenchmarks/fib.lua, benchmarks/fib.js

Compile with COIL_AUTO_PAR=0 for fair sequential timing (default auto-par would fork-join the binary recursion).


examples/perf/nsieve.hy#

Demonstrates: Sieve of Eratosthenes (Vec fill + mutation).

Runcargo run --release -- examples/perf/nsieve.hy
Output1900
Portsbenchmarks/nsieve.lua, benchmarks/nsieve.js

examples/perf/binary_trees.hy#

Demonstrates: Recursive tree alloc + walk checksum (GC-heavy).

Runcargo run --release -- examples/perf/binary_trees.hy
Output135854
Portsbenchmarks/binary_trees.lua, benchmarks/binary_trees.js

examples/perf/bool_guard.hy#

Demonstrates: if flag { break } on a bool local — a guard with nothing to fuse into *Jmpf, so it lowers to a single JMPT. Codegen anchor for invert_guard_branch (see compiler/tests/perf_metrics.rs).

Runcargo run --release -- examples/perf/bool_guard.hy
Output45

examples/call_test.hy#

Demonstrates: Calling a function for side effect; expression statement discards the return value.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn add(int a, int b) -> int {
    return a + b;
}

fn main() {
    add(3, 4);
    write_all(stdout(), to_bytes("done"));
}
Runcargo run -- examples/call_test.hy
Outputdone

Enums, match, and variants#

Sum types with unit, tuple, and record-shaped payloads.

examples/option.hy#

Demonstrates: Built-in Option, constructor calls, and match with a binding arm.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn unwrap(Option o) -> int {
    return match o {
        Option::None => 0,
        Option::Some(v) => v,
    };
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", unwrap(Option::Some(42)))));
}
Runcargo run -- examples/option.hy
Output42

examples/result.hy#

Demonstrates: Built-in Result wrapping Option, multiple match arms sharing an outer tag with different inner patterns, and inner-pattern dispatch at runtime.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn unwrap_result(Result r) -> int {
    return match r {
        Result::Err(_) => -1,
        Result::Ok(Option::Some(v)) => v,
        Result::Ok(Option::None) => 0,
    };
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", unwrap_result(Result::Ok(Option::Some(42))))));
    write_all(stdout(), to_bytes(format("%i", unwrap_result(Result::Ok(Option::None)))));
    write_all(stdout(), to_bytes(format("%i", unwrap_result(Result::Err("oops")))));
}
Runcargo run -- examples/result.hy
Output420-1

examples/scalar_enum.hy#

Demonstrates: Scalar-backed #[repr(int)] enum, Status::Ok = 200, implicit coerce to int, Show of the backing word, and default match.

#[repr(int)]
#[derive(Show, Eq, Ord, Hash)]
enum Status {
    Ok = 200,
    NotFound = 404,
}

fn label(Status s) -> string {
    return match s {
        Status::Ok => "ok",
        default => "other",
    };
}

fn main() {
    let s = Status::Ok;
    write_all(stdout(), to_bytes(format("%s %i %v\n", label(s), s, s)));
}
Runcargo run -- examples/scalar_enum.hy
Outputok 200 200

examples/assert.hy#

Demonstrates: prelude::test::assert returning Result<(), string>, with ? propagation and matched error messages.

Runcargo run -- examples/assert.hy
Outputok,assertion failed,custom

examples/panic.hy#

Demonstrates: panic "…" abort (writes panic: boom at <file>:<line>:<col>, process exits 1).

Runcargo run -- examples/panic.hy
Outputpanic: boom at examples/panic.hy:7:4 (non-zero exit)

examples/raise_try.hy#

Demonstrates: raise, postfix ?, and inferred Result return (implicit Ok wrapping).

fn parse_pos(int n, int is_neg) {
    if is_neg == 1 {
        raise "neg";
    }
    return n;
}

fn double_pos(int n, int is_neg) {
    let v = parse_pos(n, is_neg)?;
    return v * 2;
}
Runcargo run -- examples/raise_try.hy
Output10,neg

examples/coalesce.hy#

Demonstrates: ?? on Option and Result (Err is swallowed on Result).

Runcargo run -- examples/coalesce.hy
Outputbar,hi,7,9

examples/optional_chain.hy#

Demonstrates: ?. optional field access on Option plus ?? fallback.

Runcargo run -- examples/optional_chain.hy
Output42,0

examples/tree.hy#

Demonstrates: Recursive enum (Tree::Node contains child Tree values); isorecursive typing and recursive match.

enum Tree {
    Leaf,
    Node(int, Tree, Tree),
}

fn sum_tree(Tree t) -> int {
    return match t {
        Tree::Leaf => 0,
        Tree::Node(v, left, right) => v + sum_tree(left) + sum_tree(right),
    };
}
Runcargo run -- examples/tree.hy
Output6

examples/record.hy#

Demonstrates: Record-shaped enum variant (Point { x: int, y: int }), pattern destructuring in match, and field access (p.x, p.y).

Runcargo run -- examples/record.hy
Output169512 (distance² = 169, then x = 5, y = 12)

examples/derive_show_eq.hy#

Demonstrates: #[derive(Show, Eq, Ord)] on enums and classes — structural %v, ==, and < without hand-written impls.

#[derive(Show, Eq, Ord)]
enum Color {
    Red,
    Blue,
}

#[derive(Show, Eq)]
enum Point {
    Origin,
    Point { x: int, y: int },
}

#[derive(Show, Eq)]
class Cell {
    value: int,
}
Runcargo run -- examples/derive_show_eq.hy
OutputColor::Red,true,false,true,Point::Point { x: 5, y: 12 },true,false,Cell { value: 42 },true,false

examples/typeof_len.hy#

Demonstrates: compile-time typeof (FQN string constants), static len folding for string/array/tuple/dict literals, and the default Show for a class (prints the type name).

Runcargo run -- examples/typeof_len.hy
Outputint / string / (int, int) / 3 / 3 / 2 / 2 / Point / Point (one per line)

examples/length_trait.hy#

Demonstrates: len via the Length typeclass — builtin string length, a custom impl Length for Pair, and a generic T: Length helper.

Runcargo run -- examples/length_trait.hy
Output3 / 2 / 42 (one per line)

examples/derive_hash.hy#

Demonstrates: #[derive(Hash)] with recursive field.hash() — primitives (int, string, …) and nested Hash types.

#[derive(Hash)]
enum Inner {
    A(int),
}

#[derive(Hash)]
enum Outer {
    Wrap(Inner),
    Label { name: string, flag: bool },
}
Runcargo run -- examples/derive_hash.hy
Outputtrue,true,true,true

examples/spread.hy#

Demonstrates: Call-site spread for tuples and arrays.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn pair_sum(int a, int b) -> int { return a + b; }
fn triple_sum(int a, int b, int c) -> int { return a + b + c; }

fn main() {
    write_all(stdout(), to_bytes(format("%i", pair_sum(...(1, 2)))));
    write_all(stdout(), to_bytes(format("%i", triple_sum(...[10, 20, 30]))));
}
Runcargo run -- examples/spread.hy
Output360

examples/attr_decorator.hy#

Demonstrates: User-defined attr decorators with argument forwarding and stacked wrappers.

Runcargo run -- examples/attr_decorator.hy
Outputenterdo_thinghi42

examples/attr_class.hy#

Demonstrates: Class-level #[attr(...)] wrapping new Point(...) construction.

Runcargo run -- examples/attr_class.hy
OutputPoint ctor512

examples/mixed.hy#

Demonstrates: One enum mixing unit, tuple, and record variant shapes; match arms bind payload values per shape.

enum Shape {
    Empty,
    CircleR(int),
    Rect { width: int, height: int },
    Tri { a: int, b: int, c: int },
}
Runcargo run -- examples/mixed.hy
Outputthe areas 0, 25, 12, 2, one per line

examples/nested_records.hy#

Demonstrates: Nested record patterns in match (Wrap::W { inner: Inner::I { v }, name } => v).

Runcargo run -- examples/nested_records.hy
Output99

examples/chained.hy#

Demonstrates: Chained field access across nested record enums (o.x.v where x is itself a record type).

enum Outer {
    Outer { x: Inner, y: int },
}

fn read_x_v(Outer o) -> int {
    return o.x.v;
}
Runcargo run -- examples/chained.hy
Output427 (42 and 7 concatenated in one stdout stream)

IO streams#

Virtual io module (use io::{open, stdout, …};), byte / Vec<byte> buffers, files, EOF, text helpers, UDP.

examples/io_bytes.hy#

Demonstrates: byte annotation, Vec<byte> via Vec::from, len / index.

Runcargo run -- examples/io_bytes.hy
Output25532

examples/io_file.hy#

Demonstrates: open / write_all / read_to_end / close round-trip; Result + ?.

Runcargo run -- --allow-read --allow-write examples/io_file.hy
Output2

examples/io_eof.hy#

Demonstrates: Non-blocking read on an empty file returns Ok(None) (EOF).

Runcargo run -- --allow-read --allow-write examples/io_eof.hy
Outputeof

examples/io_text.hy#

Demonstrates: from_bytes (Vec<byte> → UTF-8 string) and to_bytes (string → Vec<byte>).

Runcargo run -- examples/io_text.hy
Outputhello2

examples/io_udp.hy#

Demonstrates: use io::net::udp::{bind, local_port, send_to, recv_from_wait}; — localhost echo.

Runcargo run -- --allow-net examples/io_udp.hy
Output2

examples/io_nested_host.hy#

Demonstrates: Nested IO HostInvoke — read_to_end(open(...)?) must leave the stream (not the outer native id) on the stack for MakeTuple.

Runcargo run -- --allow-read --allow-write examples/io_nested_host.hy
Output3

examples/io_nested_write.hy#

Demonstrates: Nested IO HostInvoke with outer arity > 1 — write_all(open(...)?, buf) must pack the stream (not the outer native id) into MakeTuple.

Runcargo run -- --allow-read --allow-write examples/io_nested_write.hy
Output2

See Tutorial 10 — IO streams.


Collections and type aliases#

Tuples, arrays, dicts, and type aliases.

examples/array_grow.hy#

Demonstrates: Growable Vec via Vec::from + push, reading length with len, and indexing appended elements. (arr[] = append is removed.)

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    let a = Vec::from([1, 2]);
    a.push(3);
    a.push(4);
    write_all(stdout(), to_bytes(format("%i", a.len())));
    write_all(stdout(), to_bytes(format("%i", a[0])));
    write_all(stdout(), to_bytes(format("%i", a[3])));
}
Runcargo run -- examples/array_grow.hy
Output414

examples/vec.hy#

Demonstrates: Fixed [T; N] stack locals plus Vec methods (push, pop, len, index assign).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};

fn main() {
    let fixed = [10, 20, 30];
    write_all(stdout(), to_bytes(format("%i,", fixed[1])));

    let v: Vec<int> = Vec::new();
    v.push(fixed[0]);
    v.push(fixed[1]);
    v.push(fixed[2]);
    write_all(stdout(), to_bytes(format("%i,", v.len())));

    v[1] = 99;
    write_all(stdout(), to_bytes(format("%i,", v[1])));

    let _ = v.pop();
    write_all(stdout(), to_bytes(format("%i", v.len())));
}
Runcargo run -- examples/vec.hy
Output20,3,99,2

examples/dict.hy#

Demonstrates: Anonymous structurally typed records ({ foo: 42, bar: 100 }) and field read via d.foo.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn main() {
    let d = { foo: 42, bar: 100 };
    write_all(stdout(), to_bytes(format("%i", d.foo)));
    write_all(stdout(), to_bytes(format("%i", d.bar)));
    write_all(stdout(), to_bytes(format("%i", d.foo)));
}
Runcargo run -- examples/dict.hy
Output4210042

examples/aliases.hy#

Demonstrates: type Point = (int, int);, tuple indexing p[0], and alias substitution at typecheck time (zero runtime cost).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
type Point = (int, int);

fn main() {
    let p: Point = (3, 4);
    write_all(stdout(), to_bytes(format("%i", p[0])));
    write_all(stdout(), to_bytes(format("%i", p[1])));
    write_all(stdout(), to_bytes(format("%i", distance(p))));
}
Runcargo run -- examples/aliases.hy
Output347

examples/nested_aggregates.hy#

Demonstrates: Nested aggregates — type Row = (string, int); type Table = Vec<Row>; with for and let-destructure.

type Row = (string, int);
type Table = Vec<Row>;

fn main() {
    let people: Table = Vec::from([("alice", 30), ("bob", 25)]);
    // …
}
Runcargo run -- examples/nested_aggregates.hy
Outputalice:30bob:25total:55

examples/vec_tuple.hy#

Demonstrates: Element-wise tuple zip, scalar broadcast, and unary negate.

Runcargo run -- examples/vec_tuple.hy
Output22,23,24,-1-2

examples/vec_array.hy#

Demonstrates: Static array zip, scalar broadcast, and element-wise **.

Runcargo run -- examples/vec_array.hy
Output46,45,18

examples/vec_generic.hy#

Demonstrates: Tier B scale<T: Num>((T,T), T) and Tier C shape-generic add<T: Num>(T, T) monomorphized over (int, int).

Runcargo run -- examples/vec_generic.hy
Output24,55

examples/vec_dot.hy#

Demonstrates: Named helpers dot and cross on length-3 tuples.

Runcargo run -- examples/vec_dot.hy
Output32,001

examples/vec_matmul.hy#

Demonstrates: Named helper matmul on nested [int; 2] matrices.

Runcargo run -- examples/vec_matmul.hy
Output19,22,43,50

examples/matrix_mul.hy#

Demonstrates: Nominal Matrix — * is matmul (Mul), + is element-wise.

Runcargo run -- examples/matrix_mul.hy
Output19,22,43,502

examples/generic_alias.hy#

Demonstrates: Parametric type aliases — type Pair<T> = (T, T); expands Pair<int> to (int, int) at typecheck time.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
type Pair<T> = (T, T);

fn main() {
    let p: Pair<int> = (3, 4);
    write_all(stdout(), to_bytes(format("%i", p[0] + p[1])));
}
Runcargo run -- examples/generic_alias.hy
Output7

examples/generic_enum.hy#

Demonstrates: User generic enums — enum Box<T> { Empty, Full(T) } with construct/match typed as Box<int> (same machinery as builtin Option / Result).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
enum Box<T> {
    Empty,
    Full(T),
}

fn unwrap(Box<int> b) -> int {
    return match b {
        Box::Empty => 0,
        Box::Full(v) => v,
    };
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", unwrap(Box::Full(7)))));
}
Runcargo run -- examples/generic_enum.hy
Output7

examples/generics.hy#

Demonstrates: Generic functions with a Num trait bound — one add<T: Num> body used at int and float call sites.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn add<T: Num>(T a, T b) -> T {
    return a + b;
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", add(3, 4))));
    write_all(stdout(), to_bytes(format("%i", add(10, 32))));
    write_all(stdout(), to_bytes(format("%f", add(1.5, 2.5))));
}
Runcargo run -- examples/generics.hy
Output7424.0427

examples/generic_print.hy#

Demonstrates: Format %v via the Show trait — builtin instances for primitives, a user impl Show for Point, and string::format("%v", ...).

Runcargo run -- examples/generic_print.hy
Output42hi1.5true(3,4)99

examples/existential_show.hy#

Demonstrates: Bare-class existential Show in a parameter type. The call print_any(42) packs the concrete value with its Show<int> dictionary, and show(x) dispatches through that stored dictionary.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn print_any(Show x) {
    write_all(stdout(), to_bytes(format("%s", show(x))));
}

fn main() {
    print_any(42);
}
Runcargo run -- examples/existential_show.hy
Output42

examples/hkt_container.hy#

Demonstrates: Unary higher-kinded traits (Container<F: * -> *>) with an impl Container<Option>, a polymorphic instance method first<A>, and a generic caller get<F: Container, A>(F<A>) -> A.

Runcargo run -- examples/hkt_container.hy
Output42

examples/hkt_bifunctor.hy#

Demonstrates: Binary higher-kinded traits (Bifunctor<F: * -> * -> *>) with an impl Bifunctor<Result> and a generic caller whose parameter has both an explicit kind and bound: F: * -> * -> *, Bifunctor.

Runcargo run -- examples/hkt_bifunctor.hy
Output42

examples/multiparam.hy#

Demonstrates: Multi-parameter trait Convert<A, B> with a where clause on a generic function (fn apply_cast<A, B>(A x) -> B where Convert<A, B>).

Runcargo run -- examples/multiparam.hy
Output42

examples/into.hy#

Demonstrates: Prelude conversion trait Into — impl Into<Fahrenheit> for Celsius and let f: Fahrenheit = c.into();.

Runcargo run -- examples/into.hy
Output32

examples/typeclass_dict.hy#

Demonstrates: User trait dictionaries, method sugar, and dictionary forwarding through a nested generic call.

Runcargo run -- examples/typeclass_dict.hy
Output4242

examples/typeclass_default.hy#

Demonstrates: An omitted default method calling a sibling implementation through the same dictionary.

Runcargo run -- examples/typeclass_default.hy
Output42

examples/superclass_ord.hy#

Demonstrates: Typeclass superclass / implied bounds — trait Ordered<T: Equal> stores Equal as a superclass; fn cmp_eq<T: Ordered> can call eq_val without writing T: Ordered + Equal. Flattened dict layout is subclass methods then superclass methods.

Runcargo run -- examples/superclass_ord.hy
Outputtruetruefalse

examples/constraint_kind.hy#

Demonstrates: Constraint-kind parameters (fn choose<c: * -> Constraint, T: c>(...)). The body first selects c = Ordered through lt_val, then calls eq_val through Ordered’s Equal superclass dictionary slot.

Runcargo run -- examples/constraint_kind.hy
Output42

examples/assoc_type.hy#

Demonstrates: Associated types — type Elem; in a trait, type Elem = int; in the impl, bare Elem as a method return type, open C::Elem under C: Collect, and a ground take_head(Option::Some(42)) call that pins the projection to int.

Runcargo run -- examples/assoc_type.hy
Output42

examples/gat_pointer.hy#

Demonstrates: Generic associated types — type Ref<T>; in a trait, type Ref<T> = T; in the impl, and an applied projection P::Ref<A> pinned by the selected Pointer<Option> instance.

trait Pointer<P: * -> *> {
    type Ref<T>;
    fn deref<T>(P<T> ptr) -> Ref<T>;
}

impl Pointer for Option {
    type Ref<T> = T;
    fn deref<T>(Option<T> ptr) -> T { /* ... */ }
}

fn get<P: * -> *, Pointer, A>(P<A> ptr) -> P::Ref<A> {
    return deref(ptr);
}
Runcargo run -- examples/gat_pointer.hy
Output42

examples/polyfn.hy#

Demonstrates: First-class generic functions, multi-instantiation, constrained apply-site dictionaries, rank-n forall parameters, and captured dictionary evidence that survives returning a PolyFn (app_dict_arity=0 at the use site).

Runcargo run -- examples/polyfn.hy
Output424.0424242

Modules & namespaces#

Multi-file projects using use and mod. Support files live under examples/src/.

examples/modules.hy#

Demonstrates: use foo::sadge; importing a function from another file; hex formatting.

use foo::sadge;
use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};

fn main() {
    sadge();
    write_all(stdout(), to_bytes(format("%x\n", 69)));
}
Companionexamples/src/foo/sadge.hy — defines fn sadge() printing 420 as hex
Expected output1a4 (newline) then 45 — i.e. 1a4\n45

Setup: cargo run -- --root ../coil-stdlib/src --root examples/src examples/modules.hy resolves the import (the workspace coil.toml lists the same roots for spool).


examples/modules_brace.hy#

Demonstrates: Brace-group imports from a module file (math.hy).

use math::{add, mul};
use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};

fn main() {
    write_all(stdout(), to_bytes(format("%i", add(5, 7))));
    write_all(stdout(), to_bytes(format("%i", mul(6, 7))));
}
Companionexamples/src/math.hy
Expected output1242

examples/src/foo/sadge.hy#

Demonstrates: Module support file; namespace foo::sadge, function FQN foo::sadge::sadge.

Run alonecargo run -- examples/src/foo/sadge.hy (if given its own main — this file only defines sadge, not main)
RoleImported by modules.hy

examples/src/foo.hy#

Demonstrates: Alternate / legacy module layout (single foo.hy with a top-level sadge).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
fn sadge() {
    write_all(stdout(), to_bytes(format("%x\n", 420)));
}
NoteUsed in namespace tests; not the file resolved by use foo::sadge (that resolves to src/foo/sadge.hy)

FFI (foreign function interface)#

Calling C from coil. Requires libffi.

examples/ffi_extern.hy#

Demonstrates: Compile-time extern block — no manual dload/declare in source. The compiler emits library load and symbol registration bytecode (unwraps Result, panics on failure).

use io::stdout;
use io::sync::write_all;
use string::{format, to_bytes};

extern "sum" {
    fn sum(int a, int b) -> int;
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", sum(40, 2))));
}
Runcargo run -- --root ../coil-stdlib/src --allow-dload sum --dload-trusted sum --ffi-search-path examples examples/ffi_extern.hy
Output42
Requiresexamples/libsum.so built from examples/sum.c (see ffi_sum.hy); the libc aliases (extern "c") are always denied

examples/ffi_varargs.hy#

Demonstrates: C-style varargs — bare ... on an extern declaration. Not language rest T... xs.

extern "sum" {
    fn sum_n(int n, ...) -> int;
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", sum_n(3, 10, 20, 30))));
}
Runcargo run -- --root ../coil-stdlib/src --allow-dload sum --dload-trusted sum --ffi-search-path examples examples/ffi_varargs.hy
Output60
Requiresexamples/libsum.so (sum_n in examples/sum.c)

examples/ffi_sum.hy#

Demonstrates: Userland FFI — dload / declare / invoke each return Result<_, Error>; unwrap with match (or ?). Check e.kind for typed recovery.

use ffi::{declare, dload, invoke};
use ffi::types::{Int};
use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};

fn main() {
    let lib = match dload("sum") {
        Result::Ok(h) => h,
        Result::Err(e) => panic e.message,
    };
    let sum_id = match declare(lib, "sum", (Int, Int), Int) {
        Result::Ok(id) => id,
        Result::Err(e) => panic e.message,
    };
    let n = match invoke(lib, sum_id, (40, 2)) {
        Result::Ok(v) => v,
        Result::Err(e) => panic e.message,
    };
    write_all(stdout(), to_bytes(format("%i", n)));
}
RunBuild the shared library first, then cargo run -- --allow-dload sum --dload-trusted sum --ffi-search-path examples examples/ffi_sum.hy
Build helperLinux: cc -shared -fPIC -o examples/libsum.so examples/sum.c; macOS: -dynamiclib → libsum.dylib; Windows: clang -shared → sum.dll
Output42
NoteEvery stem needs --allow-dload STEM plus --dload-pin STEM=SHA256 or --dload-trusted STEM (spool passes them from [ffi] allow, the coil.lock pins and trusted deps). --ffi-search-path locates libsum.so / libsum.dylib / sum.dll; an absolute path is not a bypass.

examples/sum.c#

Demonstrates: C companion source for ffi_sum.hy, ffi_struct_ret.hy, and ffi_callback_ret.hy (not a coil file).

int sum(int a, int b) { return a + b; }
/* also: make_point, get_doubler, … */
Compile (Linux)cc -shared -fPIC -o examples/libsum.so examples/sum.c
Compile (macOS)cc -dynamiclib -o examples/libsum.dylib examples/sum.c
Compile (Windows)clang -shared -o examples/sum.dll examples/sum.c

examples/ffi_struct_ret.hy#

Demonstrates: extern struct return from C unpacked into a record (p.x / p.y).

RunBuild the platform libsum artifact, then cargo run -- --allow-dload sum --dload-trusted sum --ffi-search-path examples examples/ffi_struct_ret.hy
Output34

examples/ffi_callback_ret.hy#

Demonstrates: Opaque function-pointer return (Ptr from ffi::types); prints 1 if non-null.

RunBuild the platform libsum artifact, then cargo run -- --allow-dload sum --dload-trusted sum --ffi-search-path examples examples/ffi_callback_ret.hy
Output1

examples/ffi_callback.hy / examples/ffi_array.hy#

Demonstrates: Callback trampolines and pointer/array FFI shapes (see source). Require the platform libsum shared library / libffi.


Classes#

examples/classes.hy#

Demonstrates: Positional ctor args, field read/write, and method calls (self).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
class Point {
    pub x: int,
    pub y: int,
}

impl Point {
    pub fn sum() -> int {
        return self.x + self.y;
    }

    pub fn set_x(int n) {
        self.x = n;
    }
}

fn main() {
    write_all(stdout(), to_bytes(format("%i", (2 * 2 + 3))));
    let p = new Point(1, 3);
    write_all(stdout(), to_bytes(format("%i", p.sum())));
    p.set_x(5);
    write_all(stdout(), to_bytes(format("%i", p.x)));
    write_all(stdout(), to_bytes(format("%i", p.sum())));
}
Runcargo run -- examples/classes.hy
Output7458

examples/static_ctor.hy#

Demonstrates: static fn constructors via Class::new(...) alongside unchanged positional new Class(...). Bodies build instances with new ClassName(...).

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
class Point {
    pub x: int,
    pub y: int,
}

impl Point {
    pub static fn new(int x, int y) -> Point {
        return new Point(x, y);
    }

    pub fn sum() -> int {
        return self.x + self.y;
    }
}

fn main() {
    let p = Point::new(40, 2);
    write_all(stdout(), to_bytes(format("%i,", p.sum())));
}
Runcargo run -- examples/static_ctor.hy
Output42,1,1

examples/match_block_self.hy#

Demonstrates: Brace-block match arm bodies that call self.method() (expression blocks, not dicts).

return match m {
    Mode::Zero => { self.get() },
    Mode::Other(n) => {
        self.get();
        n
    },
};
Runcargo run -- examples/match_block_self.hy
Output5

examples/generic_class.hy#

Demonstrates: Generic class declaration (class Cell<T>), inherent impl Cell<T>, constructor type inference (new Cell(42) → Cell<int>), and a method that returns the type parameter.

use io::{stdout};
use io::sync::{write_all};
use string::{format, to_bytes};
class Cell<T> {
    pub value: T
}

impl Cell<T> {
    pub fn get() -> T {
        return self.value;
    }
}

fn main() {
    let c = new Cell(42);
    write_all(stdout(), to_bytes(format("%i", c.get())));
}
Runcargo run -- examples/generic_class.hy
Output42

Coroutines#

Stackful coroutines via gen fn, yield, and resume. Phase 2 adds send/receive and yield from. See Tutorial: Coroutines.

examples/coro.hy#

Demonstrates: Basic suspend/resume with prints between yields.

Runcargo run -- examples/coro.hy
OutputSuspended/resumed trace (see source)

examples/operators.hy#

Demonstrates: Compound assignment, prefix/postfix increment, array and dict mutation, power, logical/bitwise operators.

Runcargo run -- examples/operators.hy
Output801125428falsetrue3

examples/coro_gen.hy#

Demonstrates: Generator-style counter (yield 0, yield 1, yield 2).

Runcargo run -- examples/coro_gen.hy
Output012

examples/coro_send.hy#

Demonstrates: Binding yield + resume h with v (ping-pong send).

Runcargo run -- examples/coro_send.hy
Outputhello

examples/coro_yield_from.hy#

Demonstrates: yield from delegation.

Runcargo run -- examples/coro_yield_from.hy
Output012

examples/coro_interleave.hy#

Demonstrates: Two independent handles from the same parameterized gen fn, resumed in arbitrary order, with resume used inline inside string::format.

Runcargo run -- examples/coro_interleave.hy
Output10,100,101,11,12,102

examples/coro_done.hy#

Demonstrates: done(h) builtin — false while suspended, true after completion.

Runcargo run -- examples/coro_done.hy
Outputfalsefalsetrue

examples/block_on_io.hy#

Demonstrates: task::block_on(coro) (use task::block_on;) — discards yields, returns completion value.

Runcargo run -- examples/block_on_io.hy
Output2

examples/io_wait_ready.hy#

Demonstrates: legacy manual multiplexing with wait_ready (deprecated, E0129). New code uses tasks: see examples/task_files.hy.

Runcargo run -- --allow-read examples/io_wait_ready.hy
Outputok

examples/task_files.hy#

Demonstrates: task::scope reading two files as concurrent tasks; each IO wait suspends only its task. See Tutorial 12 — Tasks.

Runcargo run -- --allow-read --allow-write examples/task_files.hy
Outputok

OS threads#

Native threads via use thread::{spawn, join, …}; — each worker runs on its own VM. See Tutorial 11 — OS threads.

examples/thread_join.hy#

Demonstrates: spawn a nullary function and join for its return value.

Runcargo run -- examples/thread_join.hy
Output42

examples/thread_channel.hy#

Demonstrates: channel, spawn with one argument, send / recv.

Runcargo run -- examples/thread_channel.hy
Outputhello

examples/thread_reply.hy#

Demonstrates: request/reply with two channels; spawn a worker with a (Receiver, Sender) tuple.

Runcargo run -- examples/thread_reply.hy
Outputping

examples/thread_mutex.hy#

Demonstrates: Shared mutex and with_lock from two threads.

Runcargo run -- examples/thread_mutex.hy
Output2

examples/gc_root_weak.hy#

Demonstrates: Virtual gc module — root / get / weak / upgrade / unroot.

Runcargo run --bin coil -- examples/gc_root_weak.hy
Outputpinned then pinned on the next line

examples/gc_collect.hy#

Demonstrates: unroot + collect clears a Weak (upgrade → None).

Runcargo run --bin coil -- examples/gc_collect.hy
Outputnone

examples/finalizer.hy#

Demonstrates: GC-time fn drop() on a class (fake handle close).

Runcargo run --bin coil -- examples/finalizer.hy
Outputclosed

examples/for_in_coro.hy#

Demonstrates: for x in over a coroutine — yields enter the body; completion/return does not; break mid-loop.

Runcargo run -- examples/for_in_coro.hy
Output01210

examples/range.hy#

Demonstrates: lazy Range<T: Ord> (0..n, 0..=n, float bounds), first-class range values, empty decreasing ranges. Numeric ranges collect with .to_vec() (tests/positive/range_to_vec.hy).

Runcargo run -- examples/range.hy
Output012340123561.02.03.0

examples/for_in_array.hy#

Demonstrates: for x in over an array (Item = element type).

Runcargo run -- examples/for_in_array.hy
Output123

examples/for_in_tuple.hy#

Demonstrates: homogeneous tuple for-in (Item = element type).

Runcargo run -- examples/for_in_tuple.hy
Output123

examples/for_in_custom.hy#

Demonstrates: user impl IntoIterator + impl Iterator on a class.

Runcargo run -- examples/for_in_custom.hy
Output012

Showcase projects#

Larger multi-file apps live under examples/projects/. Each project has its own coil.toml, co-located tests/, and NOTES.md.

ProjectFocusHow to run
01-todoClasses, arrays, modules./examples/projects/01-todo/demo.sh
02-adventureInteractive stdin REPL + save/load./examples/projects/02-adventure/demo.sh (or --ci)
03-echoTCP + coroutines + protocol module./examples/projects/03-echo/demo.sh

Convenience from repo root:

./examples/projects/run-demos.sh    # all demos (adventure uses transcript.txt)
./examples/projects/run-tests.sh    # co-located tests for all three

Playing 02-adventure#

Reads all of stdin (read_to_end) then splits lines — on a TTY end with Ctrl+D, or pipe a transcript. Modules: world / commands / save + entry main.

./examples/projects/02-adventure/demo.sh

Commands: look, go north|south|east|west, take / take key, inventory, save, load, help, quit.

CI / non-interactive (always under timeout; canned input in transcript.txt):

./examples/projects/02-adventure/demo.sh --ci

Per-project tests#

./examples/projects/run-tests.sh

Or cd into a project and run coil test (harness is CWD-./tests only). See examples/projects/README.md.


Quick reference table#

FileCategoryOutput (if known)
print_literal.hyBasicshello
format_literal.hyBasics42
string_fmt.hyBasicshello world42-x
show_tuple.hyBasics(1, 2){ a: 3, b: 4 }
let_test.hyBasics51020
defer.hyBasicsenterleave,021,okd7,d99,55
named_args.hyBasicsAda36Grace40
variadic.hyBasics60Hi!?
const.hyBasics42hi
loop_break.hyBasics18
fizbuz.hyBasicsFIZBUZFIZFIZBUZFIZFIZBUZ
fib.hyBasics2178309
perf/mandelbrot.hyPerf625885
perf/tak.hyPerf7
perf/fib.hyPerf2178309
perf/nsieve.hyPerf1900
perf/binary_trees.hyPerf135854
perf/bool_guard.hyPerf45
inline_wrapped_call.hyCodegen13
call_test.hyBasicsdone
option.hyEnums42
result.hyEnums420-1
scalar_enum.hyEnumsok 200 200
tree.hyEnums6
record.hyEnums / records169512
mixed.hyEnums0\n25\n12\n2\n
nested_records.hyEnums99
chained.hyEnums / fields427
io_bytes.hyIO25532
io_file.hyIO2
io_eof.hyIOeof
io_text.hyIOhello2
io_udp.hyIO2
io_nested_host.hyIO3
io_nested_write.hyIO2
array_grow.hyCollections414
vec.hyCollections20,3,99,2
static_singleton.hyStatics121
readonly_seal.hyReadonly312
dict.hyCollections4210042
gc_root_weak.hyGCpinned\npinned
gc_collect.hyGCnone
finalizer.hyGCclosed
aliases.hyTypes347
nested_aggregates.hyAggregatesalice:30bob:25total:55
vec_tuple.hyAggregates22,23,24,-1-2
vec_array.hyAggregates46,45,18
vec_generic.hyAggregates24,55
vec_dot.hyAggregates32,001
vec_matmul.hyAggregates19,22,43,50
matrix_mul.hyAggregates19,22,43,502
generic_alias.hyTypes7
generic_enum.hyEnums / types7
generics.hyTypes7424.0427
generic_print.hyTypes42hi1.5true(3,4)99
existential_show.hyTypes42
hkt_container.hyTypes42
hkt_bifunctor.hyTypes42
multiparam.hyTypes42
into.hyTypes32
typeclass_dict.hyTypes4242
typeclass_default.hyTypes42
superclass_ord.hyTypestruetruefalse
constraint_kind.hyTypes42
assoc_type.hyTypes42
gat_pointer.hyTypes42
polyfn.hyTypes424.0424242
operators.hyOperators801125428falsetrue3
modules.hyModules1a4\n45
modules_brace.hyModules1242
src/foo/sadge.hyModules(support file)
src/foo.hyModules(support file)
src/math.hyModules(support file)
ffi_extern.hyFFI42
ffi_varargs.hyFFI60
ffi_sum.hyFFI42
ffi_struct_ret.hyFFI34
ffi_callback_ret.hyFFI1
sum.cFFI(C source, not .hy)
classes.hyClasses7458
static_ctor.hyClasses42,1,1
match_block_self.hyClasses / Match5
generic_class.hyClasses42
coro.hyCoroutines(see source)
coro_gen.hyCoroutines012
coro_send.hyCoroutineshello
coro_yield_from.hyCoroutines012
coro_interleave.hyCoroutines10,100,101,11,12,102
coro_done.hyCoroutinesfalsefalsetrue
thread_join.hyOS threads42
thread_channel.hyOS threadshello
thread_reply.hyOS threadsping
thread_mutex.hyOS threads2
for_in_coro.hyCoroutines01210
for_in_array.hyCollections123
for_in_tuple.hyCollections123
for_in_dict.hyCollections12
for_in_custom.hyCollections / traits012
range.hyRanges012340123561.02.03.0

Running tests that mirror examples#

The compiler crate runs many of these as golden tests:

cargo test -p compiler --test pipeline

This is useful to verify expected output without invoking the full CLI archive path.


Arity overloads, fn values, and lambdas#

examples/overload.hy#

Demonstrates: Compile-time arity overloads — same name, different arities.

Runcargo run -- examples/overload.hy
Output15

examples/type_overload.hy#

Demonstrates: Same-arity type overloads — show(int) / show(float) / show(string) selected by argument type.

Runcargo run -- examples/type_overload.hy
Outputi:7f:1.5s:hi

examples/fn_value.hy#

Demonstrates: First-class monomorphic functions (let f = add) and positional partial application (let g = add(1)).

Runcargo run -- examples/fn_value.hy
Output423

examples/lambda.hy#

Demonstrates: Explicit-capture lambdas — fn (int x) use (y) => x + y.

Runcargo run -- examples/lambda.hy
Output42

examples/method_overload.hy#

Demonstrates: impl method arity overloads (bump() vs bump(int)).

Runcargo run -- examples/method_overload.hy
Output1116
↑ ↓ navigate ↵ open