Program Structure

Null, Option, Result & Faults

Choose Option or Result for missing values and input errors, use null for external data, and fix operations that cause faults.

Choose how your program handles missing values and failed operations. Follow an input from None to Err, then fix an array access that stops execution.

Install Topaz with First Program. For a guided introduction to these examples, start with Failures and Resources.

Handle invalid input with Result

Save this code as failures-resources.tpz.

TOPAZ
record StudyTask {
    title: string,
    minutes: int,
}

function parseMinutes(text: string) -> Result<int, string> {
    match toInt(text) {
        case Some(value) if value > 0 => Ok(value)
        case _ => Err("minutes must be a positive integer")
    }
}

function makeTask(title: string, minuteText: string) -> Result<StudyTask, string> {
    let minutes = parseMinutes(minuteText)?
    Ok(StudyTask { title: title, minutes: minutes })
}

function inspect(minuteText: string) -> () {
    print("input: {minuteText}")
    defer { print("inspection finished") }
    match makeTask("Build application", minuteText) {
        case Ok(task) => print("ready: {task.title}, {task.minutes} minutes")
        case Err(message) => print("cannot add task: {message}")
    }
}

inspect("25")
inspect("later")

In that folder, check and run the file.

BASH
topaz check failures-resources.tpz
topaz run failures-resources.tpz

Both commands exit with code 0. The program prints the error for "later" and finishes the inspection.

Output
input: 25
ready: Build application, 25 minutes
inspection finished
input: later
cannot add task: minutes must be a positive integer
inspection finished

Option holds a value in Some or represents its absence with None. Here, toInt("25") returns Some(25) and toInt("later") returns None.

Result holds a success value in Ok or an error value in Err. The function parseMinutes accepts positive integers. For missing, zero, or negative values, it returns Err with the message shown above.

In makeTask, postfix ? extracts the integer from Ok. If it receives Err, it returns that error from makeTask immediately. The final match prints either the task or the error message. To accept the second input, change "later" to a positive integer string such as "10".

Choose a representation

SituationUse or expect
A value may normally be absentOption<T> with Some(value) or None
External data contains a field that allows nullT | null
The caller needs a result or an error explanationResult<T, E> with Ok(value) or Err(error)
An invalid operation stops execution, such as an out-of-bounds accessA runtime fault

Use Option for expected absence in Topaz APIs. Use null when the external data you work with contains it.

Access a value or supply a default

Input typeExpressionResult
maybeUser: Option<{ name: string }>maybeUser?.nameSome(name) or None
Same inputmaybeUser?.name ?? "guest"The name, or "guest" when absent
configPath: string | nullconfigPath ?? "default.toml"The path, or "default.toml" when null

?. accesses a field or calls a method when the value is present. For Option, an absent value yields None. For a nullable value, it yields null. If a member already returns Option, ?. keeps one Option wrapper around that result.

?? extracts one optional layer and evaluates its right side when the left side is None or null. Both operators evaluate the left side once. An empty receiver also makes ?. skip method arguments.

target ??= value assigns when the target is None or null. The target must be mutable. For an Option<int> target, write Some(42) as the assigned value. Topaz does not add Some automatically.

Use . on ordinary values. If a union includes both Option<T> and null, separate the cases with match before accessing a member.

Find and fix a runtime fault

Save this separate program as intentional-fault.tpz.

TOPAZ
let tasks = ["Run first program", "Build application"]
print(tasks[2])

Run topaz run intentional-fault.tpz. It exits with a nonzero code.

Output
error[TPZ4001]: index 2 is out of bounds for an array of length 2
 --> intentional-fault.tpz:2:7
  |
2 | print(tasks[2])
  |       ^^^^^^^^

The array has indices 0 and 1. On line 2, change tasks[2] to tasks[1] and run again. It prints Build application and exits with code 0.

A runtime fault stops evaluation without returning None or Err. Neither ?, ??, ?., nor concurrent catches it. Invalid constant arithmetic may be rejected during checking, before execution begins.

Propagate errors and clean up

  • Apply postfix ? to a Result inside a function or closure that can return the same error value.
  • Topaz has no try blocks, exception handlers, fault catching, panic keyword, or automatic retries.
  • The built-in assert(...) requires an explicitly selected test-profile.
  • Use defer for cleanup when leaving a scope normally, including early returns through ?. Cleanup after a runtime fault is unspecified.

See Defer & Resources for cleanup order and Runtime Behavior for other operations that cause faults.