Cyclic imports
Two modules may import each other, because nothing runs when a module is imported and its exports are computed to a fixpoint, but the same cycle between top-level statements is an error.
Importing is not running. Two files that name each other's types are not a mistake, because a module contributes nothing but declarations, and a declaration does not care in which order its neighbors were read.
Example#
first.trb:
use Second from "./second"
public type First {
next: Second
}second.trb:
use First from "./first"
public type Second {
previous: First?
}Syntax#
// first.trb
use Second from "./second"
// second.trb
use First from "./first"Rules#
Imports between modules may be cyclic, exactly as imports between packages may.
std/corenamesstd/textbecauseShow.showanswers aString, andstd/textnamesstd/corebecause aStringisCompare- cutting that apart would need one package, or aStringthat is not a type of the standard library.A cycle is harmless because nothing runs when a module is imported. An imported module consists of declarations only (see Top-level code), so there is no initialization order for a cycle to break, and the exports on both sides are computed to a fixpoint.
A cycle between workspace members is still an error. Workspaces build their members in the order their dependencies require, and a member cannot depend on itself through another member - that ordering question only exists between packages, not between the files inside one.
A cycle of top-level statements is not the same question, and is still rejected. Only a file nothing imports may hold top-level statements at all; two such files cannot import each other in the first place, because each one would then be imported.
What this is not#
A cyclic import is not a design smell to break up. Two types that reference each other are ordinary in a
program with algebraic data types, and splitting the cycle across more files does not remove it, it only moves where
the use lines point.
use Second from "./second"
public type First {
next: Second
}A cycle of top-level statements is a different question, and stays an error. The rule is not about the two files naming each other; it is that a file which is imported may not hold a top-level statement at all, cyclic or not - see Top-level code for the exact diagnostic.
use Second from "./second"
print "loading first"Related#
- Top-level code - why an imported module has no initialization order to protect.
- use - the import statement that can form the cycle.
- Workspaces - the one place a cycle is still rejected: between member packages.