Zain Dana HarperQuantaLang · the effects language

What a function may do belongs in its type.

QuantaLang is a small programming language with one stubborn idea. Every function has to say, right at the top, what it’s allowed to reach out and touch — your files, the screen, the network. Those reach-outs are called effects. The function also has to be clear about which piece of memory it hands back, and how long that memory is allowed to stay alive — the part people call lifetimes. The compiler — the program that turns your code into something the machine can run — checks both, then turns it into fast native code. Reach for something you never declared, and it simply won’t build.

I built it so the compiler could answer a question I kept getting wrong on my own: what is this function actually allowed to do? It’s tested where it counts, honest about its rough edges, and the careful habit at the heart of it — say what you’ll touch, then be held to it — runs quietly under everything else here.

quantac 1.0.0 · a Rust-built compiler · effects and lifetimes, in the type

The signature stops being a suggestion.

In most languages, a function can quietly open a file or call out over the network, and nothing in its description warns you it does. QuantaLang asks each function to declare it out loud. A function lists exactly what it’s allowed to touch; if it ends up reaching for something it never put on that list, the program is turned away — and the error points right at the line that broke the promise. Memory is treated the same gentle way: which piece of memory comes back to you, and how long it’s allowed to live, is checked rather than hoped for.

Two honest questions every function should answer — what am I allowed to touch, and whose memory am I handing you — answered by the compiler that runs the code, not by a comment that hopes you read it.

Don’t take the type. Watch it refuse.

Each of these is a real file checked by the real binary — quantac 1.0.0, release build. The output is verbatim.

Exhibit I QuantaLang · effects are part of the signature
fn load_config() {
    read_file("ops.toml");        // reaches the filesystem
}

$ quantac check missing_effect.quanta
function `load_config` performs effect `FileSystem` but does not declare it
  help: add ~ FileSystem to the signature
  note: capability `FileSystem` was triggered by ambient call(s): read_file

# declare the effect, and the same check passes — and writes a receipt
fn load_config() ~ FileSystem { read_file("ops.toml"); }

$ quantac check load_config.quanta --receipt receipt.json
Type checking... OK
  "declared_effects":      { "load_config": ["FileSystem"] }
  "observed_capabilities": { "load_config": { "FileSystem": ["read_file"] } }

Touch your files without saying so, and it won’t build — the error points at the exact line that did it. Declare it instead, and it passes — and the compiler writes down what you promised, right next to what it actually saw you do.

Captured live from quantac check (Rust toolchain, release build) · the effect is built into the function and checked every time it’s called. That little receipt is the heart of it — what you promised, side by side with what really happened — and it’s honest that this is the foundation, not a finished, ship-it-tomorrow product.

Exhibit II QuantaLang · memory has an owner, and the type tracks it
fn pick<'a, 'b>(x: &'a i32, y: &'b i32) -> &'a i32 {
    y          // returns 'b where the signature promised 'a
}

$ quantac check pick.quanta
Lexing... OK (28 tokens)
Parsing... OK (1 items)
Type errors found:
  function returns `&'b i32` but expected `&'a i32`

Here’s what’s happening: the function promised to hand back one specific piece of memory, then tried to hand back a different one that might disappear sooner. The compiler catches the swap and says no. How long memory is allowed to live is a promise too — and it’s kept.

Diagnostic from compiler/src/types/error.rs, surfaced through the lifetime matching in unify.rs. An honest limit, said plainly: this memory-lifetime checking is not yet complete. It already follows memory as it passes between functions (that’s the Phase 1 work), but I haven’t finished proving every case at the caller’s side — so I won’t claim it’s complete.

Exhibit III QuantaLang · checked, then compiled to native
# an algebraic effect with a handler — parsed, effect-checked,
# lowered to C, compiled, and run:
$ quantac run examples/quickstart/effects_greeting.quanta
Hello, teammate!

That same promise-keeping follows the program the whole way down — read it, check what it’s allowed to touch, translate it into the C language, and run it. From there, one path turns it into a real program your machine can run on its own.

The C path is the one that works start to finish, and the tests prove it. The others — LLVM, WASM, SPIR-V, x86-64, ARM64, and a route that writes Rust — can produce code, but they’re still experiments. I’d rather just tell you that than let you assume otherwise.

1002 passing tests, and a short list of what doesn’t ship.

Built in Rust, with the current Cargo baseline at 1002 passed / 0 failed / 11 ignored on 2026-06-23 — up from the 868-test baseline the notes recorded on 2026-06-15. The C path carries a program all the way to something your machine can run on its own, and it’s the route the tests check from one end to the other. That’s the whole of what I’ll claim — nothing the tests won’t back up.

It isn’t winding down. It’s holding still — because the rest is built on it.

The core is shipped and steady: say what you’ll touch, be clear about your memory, checked the whole way down to native code. That’s solid ground the rest of my work stands on — not a product still chasing the next feature. Some pieces are honestly only half-built, and I’d rather you hear it from me than stumble on it. The compiler that’s meant to one day build itself is drawn up but doesn’t run yet. A few features — doing many things at once, automatic memory cleanup, and talking to code written in other languages — are designed but not yet wired into the programs it produces. And the experimental paths can make code but aren’t ready for real use. I built this on my own. Those are the rough edges I already know about — the named limits of a foundation, not a project quietly closing its doors.

Build it. Then make it reject something.

You’ll need Rust 1.70 or newer and a C compiler installed where the system can find it. Copy the project down, build it, and quantac doctor tells you the C path is good to go. Point it at the examples — or, better, write a function that fibs about what it touches, and watch it gently refuse.

$ git clone https://github.com/HarperZ9/quantalang && cd quantalang/compiler
$ cargo build --release
$ quantac doctor                       # toolchain + C-backend readiness
C backend: ready

$ quantac run examples/quickstart/effects_greeting.quanta
Hello, teammate!
GitHubHarperZ9/quantalang  ·  Emailzaindharper@gmail.com  ·  ← the map  ·  the index