Multi-file project
When a project grows, code splits across multiple files. In Zolo, each file is
a module: the entry file declares modules with mod and imports what it needs
with use. The compiler locates each file by name, in the same directory as
the file that declares the mod.
The following example shows a program with three files: main.zolo (entry
point), greeter.zolo (greeting module), and helpers.zolo (numeric
utilities). Because the files depend on each other, they must be run together —
there is no way to run them individually in the browser playground.
helpers.zolo — defines public numeric functions and a private constant:
Support module: add, double, and circle_area are public; PI is private
to the module (no pub).
// Module: helpers — numeric utilities.
pub fn add(a: int, b: int) -> int {
return a + b
}
pub fn double(x: int) -> int {
return x * 2
}
const PI: float = 3.14159
pub fn circle_area(r: float) -> float {
return PI * r * r
}
Requires the Zolo CLI/host — open in the playground or run locally.
greeter.zolo — exposes hello and farewell; the helper function
build_prefix stays private:
build_prefix has no pub — it is an implementation detail invisible to
main.zolo.
// Module: greeter
// Anything `pub` is exported; the rest is private to the module.
pub fn hello(name: str) {
let prefix = build_prefix()
print("{prefix}, {name}!")
}
pub fn farewell(name: str) {
print("Bye, {name}.")
}
// Private — called only from inside the module. It is not exposed
// in the `use greeter::...` over in main.
fn build_prefix() -> str {
return "Hello"
}
Requires the Zolo CLI/host — open in the playground or run locally.
main.zolo — entry point that orchestrates both modules. The self in the
use helpers list brings the helpers namespace into scope at the same time as
the individual names:
use helpers::{self, add, double, circle_area} allows both add(2, 3)
(direct) and helpers.add(10, 20) (qualified via namespace). To run:
zolo run main.zolo inside the multi-file/ folder.
// Feature: multi-file program with `mod` + `use`
// Structure:
// main.zolo <- entry point
// greeter.zolo <- `greeter` module
// helpers.zolo <- `helpers` module
//
// To run (from this folder):
// zolo run main.zolo
// Declares that we will use the `greeter.zolo` and `helpers.zolo`
// files as modules. `mod` resolves each one by reading the file
// from the same directory.
mod greeter
mod helpers
// Imports specific names via `use`. The `self` entry in the list brings
// the module table itself into scope alongside the destructured items,
// so both `helpers.add(...)` and the bare `add(...)` work.
use greeter::{hello, farewell}
use helpers::{self, add, double, circle_area}
fn main() {
hello("zolo")
// expected: Hello, zolo!
let sum = add(2, 3)
print("2 + 3 = {sum}")
// expected: 2 + 3 = 5
// `helpers` is bound thanks to the `self` entry in the use list.
print("helpers.add(10, 20) = {helpers.add(10, 20)}")
// expected: helpers.add(10, 20) = 30
print("double of 7 = {double(7)}")
// expected: double of 7 = 14
print("area(r=2) = {circle_area(2.0)}")
// expected: area(r=2) = 12.56636
farewell("zolo")
// expected: Bye, zolo.
}
Requires the Zolo CLI/host — open in the playground or run locally.
See also