Overview

Getting Started with Topaz

Install Topaz and run your first program with the toolchain: hello, a ten-line tour, a real fault, and a two-file module unit.

Note: Every program on this page was executed against the toolchain exactly as shown, and the printed output is pinned byte-for-byte by the site verifier. See Toolchain status for what runs today and what proves it.

Install Topaz

Install the topaz toolchain with no repo clone and no build.

Shell (macOS / Linux):

curl -fsSL https://topaz.ooo/install.sh | sh

Windows (PowerShell):

irm https://topaz.ooo/install.ps1 | iex

With npm, if you already have Node:

npm install -g topaz-lang

Then confirm it:

topaz version
OUTPUT
Topaz 5.5

You can also try Topaz in your browser, with nothing to install.

One caveat about native builds. topaz run, topaz check, and topaz emit work from the standalone binary with nothing else installed. Compiling straight to a native binary with topaz build shells out to cargo through rustup, so that one command needs a Rust toolchain present on the machine.

Your first program

Create hello.tpz:

TOPAZ
let greeting = "Hello, Topaz!"
print(greeting)

Run it:

topaz run hello.tpz
OUTPUT
Hello, Topaz!

That is the whole loop: one file, topaz run, output. No project scaffolding, no manifest, no build step.

A ten-line tour

tour.tpz touches the core of the language: match with guards and ranges, a mutable Map, a higher-order function, and option fallback:

TOPAZ
function classify(n: int) -> string {
    return match n {
        case 0 => "zero"
        case x if x < 0 => "negative"
        case 1..99 => "small"
        case _ => "large"
    }
}

let mut report: Map<string, string> = Map.new()
for n in [-5, 0, 42, 1000] {
    report.insert("{n}", classify(n))
}

print("{report.keys}")
print("{map([1, 2, 3], (x: int) => x * x)}")
print("{toInt("42") ?? 0}")
topaz run tour.tpz
OUTPUT
[-5, 0, 42, 1000]
[1, 4, 9]
42

Three things to notice:

  • match is an expression. classify returns its result directly. Arms take literals, ranges, bindings, and if guards.
  • "{…}" interpolation is the one way to format strings; it works on every value, including report.keys.
  • toInt("42") returns an optional, and ?? supplies the fallback. Nothing converts silently.

When a program stops

An out-of-bounds index is not a recoverable error in Topaz. It is a fault: the program stops and the toolchain renders a diagnostic. fault.tpz:

TOPAZ
let xs = [10, 20, 30]
let i = 7
print("{xs[i]}")
topaz run fault.tpz
OUTPUT
error[TPZ4001]: index 7 is out of bounds for an array of length 3
 --> fault.tpz:3:9
  |
3 | print("{xs[i]}")
  |         ^^^^^

The process exits nonzero. Faults mark contract violations; absence you expect to handle is modeled with optionals instead. See Error Handling.

Modules in two files

A directory of .tpz files is a unit. Files import each other by name; export is the only visibility control. util.tpz:

TOPAZ
export function shout(s: string) -> string {
    return s + "!"
}

export let greeting: string = "hello"

main.tpz, in the same directory:

TOPAZ
import util

print(util.shout(util.greeting))
topaz run main.tpz
OUTPUT
hello!

The resolver finds util.tpz next to the entry file: no manifest, no path configuration. The full rules (paths, collisions, cycles, initialization order) are in Modules.

Choosing an output path

topaz run executes through the interpreter — the reference path, and all you need for the loop above. When you want a compiled artifact, the same source lowers through two backend targets.

Rust — a native binary. topaz build lowers hello.tpz to Rust and builds a stand-alone executable:

topaz build hello.tpz --out-dir out --run

It builds out/target/debug/program offline and (--run) executes it, printing the same Hello, Topaz!. This target needs a Rust toolchain present, as noted above.

Python — generated source. topaz build --target python emits Python instead, with no Rust toolchain involved:

topaz build hello.tpz --target python --out-dir py-out

It writes program.py plus its runtime topaz_py_rt.py. Both backends are checked against the interpreter; the measured-surface evidence behind each is published on the status page.

Next steps