Errors at the top level
A ? at the top level of an entry file or a script is not a panic; it prints the error and exits with 1, walking cause() one line per link, and in the dev profile names every ? the failure went through.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
An entry file's top-level code and a script have no caller to hand a failure to. ? is still legal there - it is what
turns "the program failed" into an exit code and a message on standard error, instead of a value nobody would read.
Example#
use File, IoError from "std/fs"
fn loadConfig(path: String): Result<String, IoError> {
File.readText path
}
const config = loadConfig("app.trb")?
print configSyntax#
<result-expression>? at the top level of an entry file, a script, or a receiver scriptRules#
Top-level code, and therefore a top-level
?, is only legal in an entry file (src/main.trb, or theentryof aprogramline), a script, a receiver script, or a*.test.trbfile. Asrc/lib.trbconsists of declarations only, because it is what other packages import, and importing it must not run anything.?at the top level behaves exactly as?inside a function that returnsResult<Void, Error>does, with one difference: there is noreturnto make, because there is nothing above the top level to return into. The program ends instead.A top-level
?that hands back aFailprintserror: <the error through Show>to standard error and exits with 1. This is a different format and a different exit code frompanic, because aFailreaching the top is an expected kind of ending, not a bug.The chain is walked through
cause(), onecaused by: <...>line per link, where the error arrives as the trait-typedError. A failure that wraps another one throughError.cause()prints the whole chain, in order, the way The Error trait builds it; a concrete error type is one line:error: the server did not start caused by: app.trb: no such fileIn the debug profile, every
?that hands an error on also records where it did, and those locations print under the chain, oneat <file>:<line>:<column>line per?, the innermost first and the top-level?last - the way Zig's error return traces work:error: there is no value for `host` at acme/app/src/config.trb:27:29 at acme/app/src/config.trb:46:31 at acme/app/src/main.trb:4:24The debug profile is
dev:torb runandtorb testin the VM,torb run --nativeandtorb test --native, andtorb build --profile dev. Areleasebuild records nothing and prints nothing - its machine code is the same as without the trace - and no error type carries anything for it, because the trace is kept beside the values.Only the
?s of one chain are printed. A failure that amatchor a fallback handled on the way is not part of the next one's trace: a?whose operand succeeds drops what its operand recorded, and an entry belongs to a chain only when it was recorded after the?above it began. The trace keeps the last 64 entries of a thread, and a?whose operand waits for a task starts the chain again, because the task's failure was recorded on the thread it ran on.
What this is not#
A top-level ? is not panic, and the two must not be confused when reading a stack of output. panic prints
panic: <message> and exits with 101, from a bug the program cannot recover from; ? prints error: <...> and exits
with 1, from a failure the program already turned into a value on its way up.
fn describe(): Result<Void, String> {
Fail "the server did not start"
}
const _ = describe()?fn describe() {
panic "the server did not start"
}
describe()Both end the program; only the message, the exit code, and what a supervising process should conclude from it differ.
A trace is not a stack trace. It names the ?s the failure went through, not the calls that were active when it
was created: the function that returned the first Fail is the one the innermost line's ? called, and a panic, which
is a bug and not a failure, prints the frames of the dev profile instead (panic).
Related#
- The question mark operator -
?itself, inside a function and at the top level alike. - panic - the other way a program ends, and why the two outputs must not be mistaken for each other.
- The Error trait -
cause(), which the chain in rule 4 walks.