Zag, a Zig ripoff?

Hm, maybe not...

Zomp

Zag’s compiler.

Zomp reads your whole program and proves, before it ever runs, that no number overflows and no index runs past the end. The final build carries none of those checks, or it doesn’t build.

It takes its time: every build is a full one, with no fast mode. What comes out is native code, through LLVM.

zomp

Very slow at the development, fast & safe at the final product.

Core features

  • Everything at compile time

    Zag runs every possible thing at compile time to check for issues, so the final product is safe without paying for it when it runs. The developer waits; the final product doesn’t.

  • Ownership, no garbage collector

    Everything has exactly one owner, so the compiler knows when it can be freed. Every call says what happens to a value: lend, give or copy.

  • := picks the best type

    Not just a type that fits: Zomp works out the best one from every value the binding will ever hold, across the whole program. Where a value comes from outside, you write its type.

  • A dot narrows

    Most of the syntax is chained with dots, so you can flow with the code: str.utf8, lend.mut, list.length.

  • Native code, through LLVM

    Zag compiles to native code through LLVM.

Examples

The whole program: a MAIN, and one print from std.

hello.zg
MAIN {
    std::print.stored["Hello, World!", newln];
}
Output
Hello, World!
All examples

Pros

  • Zomp proves every overflow and bounds check at compile time, and the final build carries none of them.
  • The working build checks what Zomp can’t prove yet, whatever that costs when it runs.
  • Ownership and no garbage collector: every value has one owner, so the compiler knows when to free it.
  • := works out the best type from the whole program.
  • Failures are part of a function’s signature, not exceptions.
  • and and or always work out both sides: nothing written is skipped.
  • An old spelling is refused with an error that names the new one.
  • Native code, through LLVM.

Cons

  • Builds are slow, and every build is a full one. There is no fast development mode.
  • Where Zomp can’t prove something, the final build refuses the code until you write a guardrail, a tighter type, or no_check.
  • Every value you pass says what happens to it: lend, give or copy.
  • A value from outside the program needs its type written; := on it is an error.
  • Every failure a function can return must be handled; forgetting one is a compile error.
  • When one check guards the next, it takes two ifs, or and.then.
  • Zag is being experimented with, so please don’t expect stability: any release may change or remove anything.

Speed

  • Zag, one core: the fair comparison
  • Zag, all cores: not like for like
  • Other languages, one core
sumAdds up i × i mod 7 for 300 million numbers
  • Zag, one core0.093 s1.01× C’s time
  • C0.092 sC itself
  • Rust0.173 s1.88× C’s time
  • Go0.143 s1.55× C’s time
  • Zag, all cores0.030 s0.33× C’s time
fibRecursive Fibonacci of 35: all function calls
  • Zag, one core0.016 s1.07× C’s time
  • C0.015 sC itself
  • Rust0.016 s1.07× C’s time
  • Go0.023 s1.53× C’s time
  • Zag, all cores0.017 s1.13× C’s time
listsAppends 20 million numbers to a list, then sums it 10 times
  • Zag, one core0.039 s1.05× C’s time
  • C0.037 sC itself
  • Rust0.048 s1.30× C’s time
  • Go0.097 s2.62× C’s time
  • Zag, all cores0.034 s0.92× C’s time
sieveCounts the primes up to 100 million
  • Zag, one core0.355 s0.91× C’s time
  • C0.389 sC itself
  • Rust0.397 s1.02× C’s time
  • Go0.357 s0.92× C’s time
  • Zag, all cores0.228 s0.59× C’s time

The fair comparison is Zag on one core. On all cores, Zag spreads a loop it has proven safe across them by itself, while C, Rust and Go run the plain single-threaded code anyone would write first. fib is all function calls, so it can’t be split.

Python isn’t drawn: CPython took 15.68 s on sum, 0.52 s on fib, 8.77 s on lists, 9.26 s on sieve, between 26 and 225 times Zag’s time on one core.

Run on 15 Oct 2026, on an Apple Silicon Mac with 10 cores, with nothing else running; every Zag program is a real final build of Zomp’s, at the same optimisation level as C (clang -O3) and Rust (opt-level=3). Each program is written the plain way in each language; the time is from start to exit, best of 3, and every answer is checked against C’s.

Zag beside other languages

TopicZagIn developmentRust1.99.0
MaturityA hobby language, being experimented with: no release, and no stability to expect.Stable since 1.0. New editions are opt-in, and older ones keep compiling.
Runs asNative code: Zomp compiles through LLVM.Native code, compiled ahead of time through LLVM.
MemoryOwnership: every value has one owner, and each call says lend, give or copy. No garbage collector.Ownership and borrowing, checked at compile time; values are dropped with their owner. No garbage collector.
Overflow and boundsProven at compile time; the final build carries no checks. What can’t be proven is refused until you write a guardrail or no_check.Out-of-bounds indexing panics at run time. Integer overflow panics in debug builds and wraps in release builds by default.
ErrorsFailures are part of a function’s signature, and the caller must handle each with otherwise; forgetting is a compile error.Result values and the ? operator; ignoring a Result is a warning. Panics for the unrecoverable.
Cincl.C reads C headers while building, with Clang; extern.C declares by hand. Every call into C is a no_check site.extern "C" declarations, called in unsafe code; headers are turned into Rust with tools such as bindgen.

Checked 15 Oct 2026: versions from each language’s official release index; Rust from the Rust Book and Reference, Zig from its 0.17.0 language reference, C and C++ from cppreference (C23 and C++23 are the latest published standards; C++26 is finished, but not yet published by ISO), Go from its spec and cgo docs, Java from the Java Language Specification and JEP 454, Python (CPython) from its 3.15 documentation, Zag from its design notes. Stated behaviour, not benchmarks.

Built with

PartMade with
Zomp, the compiler, and its proverRust
Its code generationLLVM 22
Its linkinglld 22, through lld’s library and a small C++ shim
What LLVM’s C API lacks, like custom passesC++, eventually: a small wrapper, as Rust’s own compiler has
Reading C headers (incl.C)Clang 22
The runtime in every programRust, no_std
The reference interpreterRust
The checker that tests Zomp against itRust
This websiteReact Router, Shiki, Cloudflare Workers

The licence, credits and trademarks are on More.