A module is a .br file. import geometry loads geometry.br from the main
file’s directory, and import util.strings loads util/strings.br. You then
write geometry.area(...), or bring names in directly with
from geometry import area. There are no visibility modifiers: every top-level
item in a module can be imported.
import geometry # geometry.brimport util.strings as text # util/strings.br, used as `text`from geometry import Point, area # use these two names directly
fn main(): let q = geometry.Point(x=3.0, y=4.0) print(Point(x=0.0, y=0.0).dist(q), area(2.0, 3.0), text.shout("hi"))A project with modules
Section titled “A project with modules”In a project made by brine new, the main file is src/main.br, so modules live
under src/:
shapes/├── brine.toml├── AGENTS.md├── README.md└── src/ ├── main.br ├── geometry.br └── util/ └── strings.brA module holds the same items as any file: functions, structs, enums, constants
and tests. It has no main:
# Points, rectangles and areas.
const ORIGIN_X = 0.0
struct Point: x: float y: float
fn dist(self, other: Point) -> float: let dx = self.x - other.x let dy = self.y - other.y return sqrt(dx * dx + dy * dy)
struct Rect: w: float h: float
fn area(self) -> float: return area(self.w, self.h)
fn area(w: float, h: float) -> float: return w * h
test "a 2 by 3 rectangle": assert Rect(w=2.0, h=3.0).area() == 6.0# Small text helpers.
fn shout(s: str) -> str: return s.upper() + "!"
fn pad_left(s: str, width: int) -> str: if len(s) >= width: return s return " ".repeat(width - len(s)) + simport geometryimport util.strings as textfrom geometry import Point, area
fn main(): let p = Point(x=0.0, y=0.0) let q = geometry.Point(x=3.0, y=4.0) let r = geometry.Rect(w=2.0, h=1.5) print(p.dist(q), area(2.0, 3.0), r.area(), geometry.ORIGIN_X) print(text.shout("done"), "[" + text.pad_left("7", 3) + "]")
test "points are 5 apart": assert Point(x=0.0, y=0.0).dist(Point(x=3.0, y=4.0)) == 5.0brine run -q5.0 6.0 3.0 0.0DONE! [ 7]brine test Built tests [dev] in 0.09stest points are 5 apart ... oktest geometry: a 2 by 3 rectangle ... ok
test result: ok. 2 passed; 0 failed; finished in 0.02sbrine test runs the tests in the main file and in every module it imports.
Tests from a module are named with the module first (geometry: ...).
Outside a project, brine run app.br works the same way: modules are found next
to app.br.
import
Section titled “import”import geometry # use as geometry.area(...), geometry.Point(...)import util.strings # use as strings.shout(...)import util.strings as s # use as s.shout(...)import geometry as g # an alias works for any moduleimport a.b.cloadsa/b/c.brand binds the last part,c. Addas nameto pick another name.- Everything in the module is reached through the name: functions
(
geometry.area(1.0, 2.0)), constructors (geometry.Point(x=1.0, y=2.0)), types in annotations (let ps: [geometry.Point] = []), static methods, enum variants (geometry.Shape.Circle(1.0), also inmatchpatterns) and constants (geometry.ORIGIN_X). - Paths are always relative to the main file’s directory, also in imports
written inside other modules: in
src/util/strings.br,import geometryloadssrc/geometry.br. - Modules may import each other, including in a cycle.
from ... import
Section titled “from ... import”from m import a, b makes items of m usable without the m. prefix:
from geometry import Point, Rect, area, ORIGIN_Ximport geometry # you can import the module too
fn main(): let p = Point(x=1.0, y=2.0) print(area(2.0, 3.0), geometry.area(1.0, 1.0), p, ORIGIN_X)Two rules keep names unambiguous:
from m import xonly imports items defined inmitself. Ifmimportedxfrom somewhere else, import it from there.- A name can’t be both imported and defined in the same module.
from geometry import Point, area
fn area(r: Point) -> float: return r.x * r.y
fn main(): print(area(Point(x=2.0, y=3.0)))error[E0202]: `area` is imported but this module already has that name --> src/main.br:1:29 |1 | from geometry import Point, area | ^^^^ imported here3 | fn area(r: Point) -> float: | ---- also defined here | = help: rename one of them, or use `import geometry` and write `geometry.area` = run `brine explain E0202` for more about this errorerror: could not compile due to 1 errorA misspelled name is E0201, with a suggestion:
error[E0201]: module `geometry` has no item `Pointt` --> src/main.br:1:22 |1 | from geometry import Pointt | ^^^^^^ not found | = help: did you mean `Point`? = run `brine explain E0201` for more about this errorerror: could not compile due to 1 errorMissing modules
Section titled “Missing modules”import geometryimport shape
fn main(): print(geometry.area(1.0, 2.0))error[E0701]: module `shape` not found --> src/main.br:2:1 |2 | import shape | ^^^^^^^^^^^^ expected a file at `src/shape.br` | = help: modules are `.br` files next to the main file; `import a.b` loads `a/b.br` = run `brine explain E0701` for more about this errorerror: could not compile due to 1 errorChecking one module
Section titled “Checking one module”brine check src/geometry.br type-checks and proves a module on its own, and
brine test src/geometry.br runs its tests. brine run needs a file with
fn main (error E0703 otherwise). brine fmt formats every .br file in the
project.
- One file is one module.
import a.bloadsa/b.brrelative to the main file’s directory and bindsb(or theasname). - Every top-level item is importable; there is no
puborprivate. from m import ximports only items defined inm.- A name can’t be both imported and defined in one module.
- Each module’s tests run with
brine testonce the main file imports it.