File Imports
The use Clause
use is a top-level clause (like type), no semicolon. It imports a module or a file:
use Core.print
File Imports
Only relative paths are supported. The compiler resolves imports dynamically:
/* main.ft */
// adds all public definitions of utils.ft
use "utils.ft"
def main():
// from utils.ft
i32 res = add(5, 6);
/* utils.ft */
def add(i32 x, i32 y) -> i32:
return x + y;
Subdirectories work too: use "subdir/file.ft".
Aliasing
// any use can be aliased, even `use Core.print`
use "add.ft" as a
def add(i32 x, i32 y) -> i32:
// must qualify through the alias
return a.add(x, y);
Types from aliased files are qualified too:
use "data.ft" as d
def main():
d.Vec3 v3 = d.Vec3(10.0, 20.0, 30.0);
Alias Chains
Aliased imports become part of the file's aliases, so they chain:
/* main.ft */
use "utils.ft" as u
def main():
// reaches through utils.ft's alias 'a' to add.ft
u.a.add(10, 20);
Without an alias you cannot see another file's aliases, only its public definitions.
Namespaces
Every file is a namespace with three sections:
- public: all definitions in the file; visible to importers.
- private: the public definitions of directly imported files (depth-1 visibility).
- alias: this file's aliased imports; only reachable if the file itself is imported with an alias.
Include an entire subsystem through one alias:
use "lib.ft" as lib
def main():
lib.math.calculate_something();
lib.render.render_something();
Relative Path Rules
- Go up with
..:use "../file.ft". - Escaping the compiler's working directory is an error (by design, for security and reproducibility).
- Circular dependencies between files are allowed.