Top-level code
A statement outside every declaration is only allowed in an entry file, a script or a test file, and a top-level const of a module has to be known at compile time.
A file that nothing imports has no initialization order to protect, so it is free to run statements from top to bottom like any other program. A file that is imported is not: it only ever contributes declarations.
Example#
use File from "std/fs"
const text = File.readText("project.trb")?
print text.lines().length()Syntax#
const <name> = <compile-time expression> a module's only top-level statement
<any statement> legal in an entry file, a script, or a *.test.trb fileRules#
An entry file may hold top-level code, and so may every file that nothing imports. The entry files are named, not configured:
src/main.trb, theentryof aprogramline of project.trb, and every*.test.trbfile. An entry file is never importable - auseof one is an error at theuse- andsrc/lib.trbof a named package is never one, because it is what other packages import. Every other file may hold top-level code exactly when nothing imports it, which is what makes a receiver script, the files ofexamples/tourand a loosescratch.trbscripts.torb check src/main.trbchecks the files that file imports through a relative path as well, so top-level code in one of them is reported even when only the entry file is named, andtorb buildrefuses the program.A
*.test.trbfile consists of nothing but top-levelgroupandtestcalls, wherever it lies in the package. The test framework is ordinary functions, so a test file is a script like any other.In an entry file, a script or a test file, a top-level
?ends the program with the error, printed and exited the same way as any other top-level failure (see Result for the exact text and exit code).await()is allowed at the top level of an entry file or a script, exactly as it is inside a function that returns aTask.const created = spawn({ 1 + 1 }) print created.await()A top-level
constof a module has to be known at compile time. Literals, unary minus, the operators of the built-in number types and ofBool, string interpolation of such, a tuple, list or map literal of such, and a constructor or case-constructor call whose arguments are such all qualify. A function call does not, and neither does anativecall.fn greeting(): String { "hello" } const message = greeting()A constant expression that overflows, divides by zero, or produces
nanis a compile error at that expression. This is the same rule as for any other overflow written in the source: caught where it is written, rather than at the moment the module happens to be loaded.A module's top-level
constbinds one name, never a pattern.const (quotient, remainder) = divide(7, 2)destructures inside a function body or the top level of a script, but not here:A module's `const` binds one name, and, for apublic const,An exported `const` binds one name. A name another file imports has to be one thing.const (a, b) = (1, 2)The top-level code of the entry file is the program, and no function is called for it.
fn main()is an ordinary function: nothing calls it unless the top-level code does. An entry file with no top-level code at all - declarations andconsts only - has nothing to run.fn main() { print "main runs because the top-level code calls it" } main() // prints main runs because the top-level code calls itpublic constexports the constant; there is nopublic varat the top level of a module. A module has no mutable state, so nothing a top-levelvarcould export exists in the first place - see Visibility.A top-level
varis changed by the statements of its file and by nothing else. The statements - the initializers of top-levelconsts among them - run in the order they are written, and a closure written straight as the argument of a call that only calls it runs while its statement does. Afnmay run anywhere, also while avaraccess to the declaration is open (Exclusivity), and so may a closure that is kept: both read a top-levelvar, and neither changes one. What a function has to change, it takes as avarparameter.Reading is the language's rule and not built yet:
torb checkaccepts a function, a closure or a test's body that reads a top-levelvar, and neither the VM nor the native back end runs one:torb runandtorb testsay that such a read is not supported yet, in the VM or natively. Until they do, hand the value over as a parameter, or copy it into a top-levelconstand read that.fn addTo(var sum: Int, amount: Int) { sum = sum + amount } var total = 0 addTo total, 5 print totalDoes not compilevar total = 0 fn bump() { total = total + 1 } bump() print total // error: `total` is a top-level `var`, and only the statements of its file change itDoes not compilevar total = 0 const reset = { total = 0 } reset() print total // error: This closure changes the top-level `var` `total` and may outlive its statementA top-level
constof an entry file, a script or a test file is evaluated once, when its statement runs, and a function that reads it reads that value. However many functions read it, and however often, the initializer runs exactly once, in the order the statements are written. A function that reads theconstbefore its statement ran - called from a statement above it - panics at the read:The top-level const `table` is read before its statement ran.fn loaded(): List<String> { print "loading" ["alpha", "beta"] } const table = loaded() fn count(): Int { table.length() } print count() print count() // prints loading // prints 2 // prints 2
What this is not#
Top-level code is not something a module can opt into. Whether a file may hold a statement outside a declaration
follows from its name and from whether anything imports it. Nothing in the file itself changes that, and nothing in
project.trb does either: no setting makes src/lib.trb an entry file.
use File from "std/fs"
const text = File.readText("project.trb")?
print texttype Config {}
print "loading"Related#
- Visibility -
publicat the top level, the other half of what a file exports. - Cyclic imports - why a module having no initialization order is what makes a cycle harmless.
- Result - what a top-level
?prints and exits with.