Topaz is a compact language for application intent. It reads like Python or TypeScript but prefers a single, consistent way to express each common idea. The same rules apply whether code is written by a developer or generated by a tool.
Rust remains the right tool when you need direct control of the machine. Topaz operates one layer higher for command-line tools, data transformation, service logic, configuration, and orchestration of SQL, shell, and paths. You can run the same source directly or build a native program, Python package, or web artifact.
This page explains where the language fits and how its code feels. It is not an introductory tutorial. If you are new to Topaz, follow the Learning path or run your first program in the Playground. Use Syntax at a Glance for a concise overview of the language, and read the language philosophy to understand its design choices.
The examples below are verified and executed using the Topaz toolchain.
What Topaz code feels like
Unicode-first
Identifiers support Unicode from the lexer level upward. Domain terms remain in your native language rather than becoming romanized approximations.
function greet(name: string, language: string) -> string {
return match language {
case "한국어" => "안녕하세요, {name}님!"
case "Русский" => "Привет, {name}!"
case _ => "Hello, {name}!"
}
}
let 사용자 = "김토파즈"
print(greet(사용자, "한국어"))
print(greet("Topaz", "Русский"))안녕하세요, 김토파즈님!
Привет, Topaz!사용자 is a standard variable. Unicode identifiers are a normal part of the language. Topaz does not silently rewrite entered names, and the module resolver rejects identifiers that cause confusion.
A small, closed surface
Common choices have a canonical form. Recoverable failures use Result, expected absence uses Option, resource cleanup uses defer, and match evaluates whether all cases are covered. The language fixes these choices so that no file diverges into its own dialect.
function parsePort(raw: string) -> Result<int, string> {
let n = toInt(raw) ?? -1
if n < 1 {
return Err("not a port: {raw}")
}
return Ok(n)
}
function startup(raw: string) -> Result<string, string> {
defer print("config closed")
let port = parsePort(raw)?
return Ok("listening on {port}")
}
print("{startup("8080")}")
print("{startup("http")}")config closed
Ok(listening on 8080)
config closed
Err(not a port: http)The ? operator propagates an Err to the caller, while defer executes on every exit path. That is why config closed appears before both results.
Templates keep intent structured
The template registry includes p, r, sh, and sql. For example, p"..." is a path template, while sql"..." keeps SQL text separate from interpolated parameters instead of collapsing everything into a single string.
let table = "users"
let q = sql"select * from {table} where active = {true}"
print("{q}")<sql template, 3 part(s), 2 interpolation(s)>The output displays a structural summary. The template retains the distinction between literal text fragments and interpolated values.
Check once, choose an output
Topaz is statically typed. The checker validates the complete program before execution.
type TrafficLight = "red" | "yellow" | "green"
function next(light: TrafficLight) -> TrafficLight {
return match light {
case "red" => "green"
case "green" => "yellow"
case _ => "red"
}
}topaz run parses, resolves, checks, and executes the program. From that same source, topaz emit and topaz build create alternative outputs. The Rust target produces a self-contained native binary. The Python target writes program.py alongside its support file topaz_py_rt.py.
Rust and Python outputs are tested against identical language behavior. See Toolchain Status for current support and target-specific limits.
topaz build app.tpz --target python --out-dir py-outWhen not to use Topaz
Use Rust, C, or Zig instead if you need direct ownership and lifetime control, unsafe boundaries, embedded targets, manual performance tuning, or full access to a systems ecosystem. Topaz's narrow scope imposes trade-offs when you require full control.
Topaz targets high-level application workflows: deployable application logic without a systems-level source surface, domain language expressed in code, and a minimal grammar that developers and tools can produce consistently. When that describes your project, proceed with the Learning path.
One way to say it.