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.
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.
topaz check failures-resources.tpz
topaz run failures-resources.tpzBoth commands exit with code 0. The program prints the error for "later" and finishes the inspection.
input: 25
ready: Build application, 25 minutes
inspection finished
input: later
cannot add task: minutes must be a positive integer
inspection finishedOption 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
| Situation | Use or expect |
|---|---|
| A value may normally be absent | Option<T> with Some(value) or None |
External data contains a field that allows null | T | null |
| The caller needs a result or an error explanation | Result<T, E> with Ok(value) or Err(error) |
| An invalid operation stops execution, such as an out-of-bounds access | A 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 type | Expression | Result |
|---|---|---|
maybeUser: Option<{ name: string }> | maybeUser?.name | Some(name) or None |
| Same input | maybeUser?.name ?? "guest" | The name, or "guest" when absent |
configPath: string | null | configPath ?? "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.
let tasks = ["Run first program", "Build application"]
print(tasks[2])Run topaz run intentional-fault.tpz. It exits with a nonzero code.
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 aResultinside a function or closure that can return the same error value. - Topaz has no
tryblocks, exception handlers, fault catching, panic keyword, or automatic retries. - The built-in
assert(...)requires an explicitly selectedtest-profile. - Use
deferfor 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.