Skip to main content
Everything on this page is built and tested: cross-checked against the language’s compiler/src, mz harness definition, and the example programs CI runs through mz run with their output compared, at language main be88017, the release of 8 October 2026 (mzizi#91). It is a slice of RFC-0013, not all of it: the rest of the RFC is design, and what is not built lists it. The tracker rows these features belong to are still 🟡 in the file (what still has to be built).
A program is a Mzizi file that runs. Its first line is program <name> and its last is end program <name>. It holds fns and, since control flow landed, enums; every statement lives inside a fn. Exactly one fn main, with no parameters, is the entry point, and a program’s output is what it prints. One program per file. mz run checks a program, lowers it to a Rust package with no dependencies, builds it with Cargo and runs it. mz build writes the same package. A program is the second thing in Mzizi that lowers to Rust, after a service; no component lowers.

The smallest program

examples/hello.mz, verbatim:
examples/hello.mz

Functions, bindings and when

examples/fib.mz, verbatim. It recurses, binds with let and var, assigns, branches with when and else, and interpolates.
examples/fib.mz
examples/fib.expected
  • fn name(a: int, b: text): int … end fn name: typed parameters, a return type or none, calls and recursion. Every path of a function with a return type returns (MZ0906); a wrong call is MZ0905, quoting the signature.
  • let binds a value once; var binds one you assign with =. Scope is the block. There is no shadowing (MZ0921), a name is readable from the line after its binding to the end of its block (MZ0920), and assigning to a let is MZ0922. Python’s bare first assignment, Go’s := and Rust’s let mut each get a fix.
  • when / else when / else, closed by end. A condition is a bool and nothing else: Mzizi has no truthiness (MZ0712).
  • return ends a function early. print(value) writes one value’s text form and a newline; to print several, interpolate them into one text.
  • Comments are lines starting with ##. // and # are MZ0911, with ## as the exact fix.

Values: int, float, bool and text

int and float never mix. 1 + 1.5 is MZ0912, with the exact fix 1.0 on an int literal and the guess x.to_float() on anything else. A float prints in the shortest form that reads back exactly: 1.0, 0.30000000000000004, 1.0e21, inf, nan. The numeric methods are postfix, so -2.pow(2) is -(2.pow(2)):

Expressions and operators

Highest precedence first, as RFC-0013 §3.5 orders the operators that are built: Equality is is and is not. ==, !=, &&, || and ! are MZ0910, each with an exact fix to the Mzizi word. += and ++ are MZ0918; str(x) and x.to_string() are MZ0962, with the exact fix "{x}". examples/numbers.mz prints its arithmetic, and numbers.expected holds what it prints.

Control flow

From examples/control.mz (an excerpt; the file is in the repository, and CI compares its output with examples/control.expected):
examples/control.mz (excerpt)
  • match <value> takes case lines, each listing one or more values (case 6 7), then an optional else, over an enum, an int, a text or a bool. It is checked for exhaustiveness: a missing case is MZ0930, naming the missing variants, and a case that can never run is MZ0931, whose exact fix deletes it. A match over a float is MZ0711: compare a float with when.
  • for each i in range(a, to = b) counts from a up to but not including b. range is read only on a for each line; for each over a list waits for lists.
  • while <condition> is the one conditional loop; while true with a break is the loop that ends from inside. break and continue act on the innermost loop, and are MZ0935 outside one.
  • when and match as values. Either may be the whole value of a let, a var, an assignment or a return, each branch one expression line; nowhere else, and there is no ternary (MZ0932).
  • Other languages’ spellings are fixed. elif, else if, switch, default:, case _ and _ => are MZ0933; for x in xs, for (const x of xs), loop and range(n) are MZ0934, each with an exact fix. An else when chain over one enum’s variants is MZ0936, with a guess fix rewriting it as a match.
Enums. A program declares an enum, one variant per line, closed by a bare end. A variant is written bare where the expected type settles its enum, and <enum>.<variant> where two enums share it. Variants compare with is, order by declaration and print as their names. A variant may carry columns, a name and a literal each, read with a dot (problem.say), as in examples/errors.mz below.

Errors: result, error and try

examples/errors.mz, verbatim:
examples/errors.mz
examples/errors.expected
  • A function that can fail returns result(T, E), or result(none, E). return v returns success, return error(e) returns failure, and return r passes a result of the function’s own type through.
  • A caller matches the result, with exactly two cases, case ok <name> and case error <name>, or propagates its error with a prefix try, in a function that returns a result with the same error type.
  • Any other use of a result is MZ0950: discarding it, printing it, comparing it, passing it or holding it in a var. A result is never a parameter, nor inside another result.
  • fn main may return result(none, E). When it returns an error, the program writes mz: error MZ0992: main returned an error: <the error's text form> to standard error and exits 1.
  • Other languages’ idioms are MZ0952: Ok(v) (exact v), Err(e) (exact error(e)), Rust’s postfix ? (exact prefix try), throw e and raise e (return error(e)), and .unwrap() and .expect(…), which have no fix: an error is never turned into a crash.

mz run

  1. Check. On any error it prints the diagnostics, exits 3, and does not build.
  2. Lower. It writes a Cargo package with no dependencies into <name>-<path hash> under $MZ_CACHE_DIR, or mzizi/mz-run/ under $XDG_CACHE_HOME or ~/.cache. With none of the three set it exits 2 and names them; it never falls back to the system’s temporary directory.
  3. Build. cargo build --offline --quiet, with --release when asked. No dependencies means no network.
  4. Run. The binary runs with the terminal’s standard input, output and error. Standard output belongs to the program; everything mz run writes of its own goes to standard error.
Every exit status means one thing. mz run departs from the other commands, where 1 means errors, because 1 belongs to the program it runs: RFC-0013 §13 also designs exit 70 and MZ0993 for a runtime failure, and mz run --agent for NDJSON on standard error. Neither is built: mz run --agent exits 2. The lowering. Every value is owned and no reference or lifetime is emitted: a text read is a .clone(). result(T, E) is Rust’s Result<T, E> and try e is e?; an enum is a Rust enum; a match on an enum or a bool has no _ arm unless it has an else, so rustc checks exhaustiveness again; for each i in range(a, to = b) is for i in a..b. The generated code holds no unwrap, expect, panic! or unsafe, which a test checks.

Nesting is capped

A program’s blocks and expressions nest at most 32 deep together, and an expression’s tree of binary operators at most 64. Past the cap is one MZ0411 per file, not a stack overflow. compiler/tests/robustness.rs holds every case to a 1 MiB stack.

What is not built

These are designed in RFC-0013 and are not in the compiler. Each is MZ0919, which says the form is designed and not built, or another code that names it:
  • Lists, maps and sets in a program, indexing, and for each over a list (C7).
  • Text methods (C6), records and methods (C8), options in function bodies, and a decimal type.
  • Named arguments beyond range’s to, try … via f (MZ0955), and a match stub as the fix for MZ0950.
  • A program’s contract block, mz test, mz run --agent, and mz outline, mz ir and mz hash on a program, which exit 2.
  • Modules: one program per file, and nothing is imported.
The benchmark’s prompts do not describe programs yet, so no benchmark arm knows about them, and nothing has been measured. Whether an agent writes these forms well is for the benchmark to find out. See Status and the compiler for every MZ09xx code.