Modules
Splitting a game across files in Balaur Script: use, pub and internal, how a file is found, constants, types and engine modules.
ในหน้านี้
A file is a module. use name; links name.bs, and its pub items read as name::item.
// util.bs
pub class Rect { pub w: float, pub h: float }
impl Rect {
pub fn area() -> float { self.w * self.h }
}
pub const SCALE: float = 2.0;
pub fn grow(r: Rect) -> Rect {
Rect { w: r.w * SCALE, h: twice(r.h) }
}
fn twice(x: float) -> float { x * 2.0 }
use util;
pub fn area() -> float {
let r = util::grow(util::Rect { w: 1.0, h: 2.0 });
r.area() + util::SCALE
}
// area() == 10.0
Who may name what
Every function, constant, struct, class, enum, field and method has one of three reaches.
| Written | Who may name it |
|---|---|
| nothing | its own file |
internal |
every file of its package |
pub |
every file |
A file's package is the addons/<name> or deps/<alias> folder it sits in, or else the project.
// secrets.bs
fn hidden() -> int { 1 }
pub class Vault {
pub id: int = 1,
code: int = 42,
}
impl Vault {
pub fn label() -> str { self.mask() }
fn mask() -> str { "#{self.id}" }
}
use secrets;
pub fn broken() -> int { secrets::hidden() }
// error: 3:26: `hidden` is private to `secrets`: mark it `pub` there
A field and a method follow the same rule, and a literal may not set a field its file keeps.
use secrets;
pub fn peek(v: secrets::Vault) -> int { v.code }
pub fn open(v: secrets::Vault) -> str { v.mask() }
pub fn make() -> secrets::Vault { secrets::Vault { code: 7 } }
// error: 3:42: `Vault.code` is private to `secrets`: mark it `pub` there
// error: 4:42: `Vault.mask` is private to `secrets`: mark it `pub` there
// error: 5:35: `Vault.code` is private to `secrets`: mark it `pub` there
internal opens an item to the other files of its addon, and no further.
// addons/kit/core.bs
internal fn seed() -> int { 7 }
pub fn roll() -> int { seed() + 1 }
use addons::kit::core;
pub fn open() -> int { core::roll() }
pub fn broken() -> int { core::seed() }
// error: 4:26: `seed` is internal to `addons/kit`: mark it `pub` there
pub says more than the others on two things. A pub free function is one the engine may call, and a pub
field with a default is a property a scene tunes. A field other files read and no scene
should set is internal.
The engine and node.call reach a method by its name as the script runs, so its hooks need no mark.
How a file is found
use util; looks for util.bs beside the file, then in each folder above it, up to the
project root. use a::b; is a/b.bs, and its items read as b::name.
| Written | File | Items read as |
|---|---|---|
use util; |
util.bs |
util::clamp |
use combat::damage; |
combat/damage.bs |
damage::roll |
use addons::gamend::core; |
addons/gamend/core.bs |
core::query |
Files may use each other in a circle, and a file may use the file that uses it.
Scripts and modules
A file with a class named after it can be attached to a node, and it is a script. A
file without one is a plain module that others use. A script's other items are a module too, so
use spinner; works from another script.
Types across files
A type reads by its path in every position: in a literal, in a signature and in a pattern.
// shapes.bs
pub enum Shape { Circle(float), Empty }
use shapes;
fn area(s: shapes::Shape) -> float {
match s {
shapes::Shape::Circle(r) => r * r,
shapes::Shape::Empty => 0.0,
}
}
pub fn run() -> float { area(shapes::Shape::Circle(2.0)) }
// run() == 4.0
Engine modules
log::, math::, input:: and the rest need no use. They come with the engine, every call is typed
against it, and the script modules reference lists them. A call the engine does not
have stops at compile time.
pub fn broken() { nope::call(); }
// error: 1:19: the engine has no `nope::call`
Saving
Saving a module reloads every script that uses it, and each object keeps its fields across the reload.