Why Zith?

Zith is a systems language with safety, expressiveness, and a small, composable core.
No GC. No borrow checker. No hidden allocator.

Compiled, statically typed, and memory-safe by default — with low-level control when you need it and high-level ergonomics when you don't.

1. Types That Work With You

Structs, enums, components, unions, generics — the basics are here and work as expected. See Type System.

struct Point { [x, y, z]: f32 }

fn dot(a: view Point, b: view Point): f32 {
    a.x * b.x + a.y * b.y + a.z * b.z
}

Unions are runtime tagged. dyn gives dynamic type erasure with compile-time safety. is narrows both, letting you operate on the concrete type inside each branch:

union Value { i32, f64, string }

fn handle(v: dyn Value) {
    if (v is i32) {
        v += 32;            // v is i32 here
    } else (v is f64) {
        @println("{v:.2}"); // v is f64 here
    }
}

No manual type switches. No unsafe downcasts. The compiler tracks the type through every branch.

2. Data Flows Forward

The -> operator pipes values left to right. .. refers to the previous value. See Control Flow.

getData() -> process(..) -> validate(..) -> save(..);

Inline blocks and comma sub-chains keep side-effects local without breaking the flow.

3. Errors Are Just Values

No exceptions. No try/catch. ?T for optionals, T! for results. Propagate with ? or !. Recover with or. See Error Handling.

fn loadConfig(path: string): Config! {
    let file = File.open(path)!
    let data = file.read()!
    parse(data)!
}

let name = ?user.name or "guest";
let data = !primary() or backup() or defaultData;

with bundles multiple fallible calls, catch handles any failure:

with (connectDb(), user: getUser(id)) {
    process(user);
} catch (err) {
    log(err);
}

4. The Combo — Chain + Error Handling

This is where Zith pulls ahead of most systems languages. Chain flow and error propagation together:

readFile("config.toml")
    -> decode(..)!
    -> validate(..)?
    -> apply(..);

Compare to Go, where the same logic is buried in boilerplate:

// Go
data, err := readFile("config.toml")
if err != nil { return err }
decoded, err := decode(data)
if err != nil { return err }
if validated, err := validate(decoded); err == nil {
    err = apply(validated)
}
return err

The Zith version does the same thing — read, decode, validate, apply — without a single if err != nil. The ! propagates errors out; ? continues on null; the chain keeps the data moving forward.

Recovery stays on the same line:

readFile("config.toml") ->
    { decode(..)! -> validate(..)? -> apply(..) }
    or fallbackConfig();   // any failure -> use default

Or with fail blocks for contextual error handling:

loadConfig {
    readFile("config.toml")
        -> decode(..)!
        -> validate(..)!
} fail loadConfig(err) {
    if (err is NotFound) { continue(defaultConfig()); }
    throw Error{ context: "load failed", cause: err };
}

A real-world example — processing a request pipeline:

parseRequest(raw)!
    -> authenticate(..)!
    -> validate(..)?
    -> queryDb(..)!
    -> marshal(..)
    -> send(..);

In Go this is ~30 lines of if err != nil. In Zith it is one.

5. How Does This Stay Safe?

Node Resource Analysis (NRA).

No borrow checker. No garbage collector. No reference counting. The compiler statically tracks every value's ownership, lifetime, and aliasing — and catches misuse before the program runs.

var a = Point { x: 1.0, y: 2.0 };
let b = a;       // b owns the data; a is now dead
// a.x           -- compile error: a is dead
a = Point{3, 4}; // fine: reassignment creates a new node

For borrowing, two keywords cover most code:

Keyword Meaning
lend Exclusive mutable borrow
view Read-only borrow (many can coexist)
fn scale(p: lend Point, factor: f32) { p.x *= factor; }

fn length(p: view Point): f32 {
    sqrt(p.x * p.x + p.y * p.y)
}

For advanced ownership: unique (single owner), share (multiple mutable names), belong (part-of relationship for back-pointers).

Safe by default. Zero runtime overhead. No ceremony.

6. Low-Level Control, Not Low-Level Ceremony

C interop is first-class — include headers directly, call functions immediately. See Raw & Unsafe.

import "openssl/ssl.h";
SSL_CTX_new(method);

When you need to bypass safety, raw fn and unsafe blocks are explicit and scoped:

raw fn readRegister(addr: opaque): u32 {
    unsafe {
        let ptr = addr as *u32;
        *ptr
    }
}

The Trust capability lets you expose safe wrappers over unsafe internals:

trait MMIONode extends Trust {
    raw fn read(self, offset: u64): u32 {}
    raw fn write(self, offset: u64, val: u32) {}
}

fn safe_copy(src: view MMIONode, dst: lend MMIONode) {
    let v = src.read(0x00);
    dst.write(0x00, v);
}

7. Scoped Contexts for DSLs

Group macros, operators, and DSLs under use blocks. No global pollution. See Contexts.

use SQL QueryBlock {
    SELECT * FROM users WHERE id = :id
}

// Outside, SQL syntax is unavailable

8. Flow Functions & State Machines

Built-in state machines via markers, docks, and jumps for embedded, OS, and game loops. See Control Flow.

flow fn scheduler(): noreturn {
    marker ContextSwitch(next: TaskId) {
        saveRegisters();
        loadTask(next);
    }
    dock { jump ContextSwitch(nextTask); }
}

9. Comptime & Reflection

const fn and const blocks for compile-time computation. @ intrinsics for reflection and type manipulation. See Intrinsics.

const fn processData(data: []char): JsonValue { ... }
const parsed = processData(AssetData);

// Reflection at compile time
let isStruct = (T is @struct);
for (member in @members(MyStruct)) {
    @println("{}: {}", member.name, member.type);
}

10. Scenes for Memory Regions

Perfect for games, simulations, and modular applications — isolated memory regions with automatic cleanup. See ECS & Scenes.

scene MainMenu {
    entity MenuButton { /* ... */ }
    entity TextDisplay { /* ... */ }
}

scene GameLevel {
    entity Player { /* ... */ }
    entity Enemy { /* ... */ }
}

transition(MainMenu, GameLevel);   // old scene dies, new scene allocates

Comparison with Rust

Feature Rust Zith
Memory Safety Borrow checker NRA (ownership types)
Learning Curve Very steep Gentle
Lifetimes Explicit annotations Implicit through types
Error Handling Result/Option + macros Failable types + chain flow
DSLs Macros only Contexts + words + macros
State Machines External crates Built-in flow fn / markers
Compile Time Slow Fast
Ecosystem Large Growing

Real-World Use Cases

Perfect For:

Consider Alternatives If:

Getting Started

  1. Installation — Set up Zith in minutes
  2. Quick Start — Write your first program
  3. Language Guide — Deep dive into features

Zith proves you don't have to choose between safety and simplicity.
Zith — A systems language with a small core and a large toolbox.