Modules
Lattice's module system allows programs to be split across multiple source files.
Modules are loaded via import statements, executed once, and their
exports are cached for subsequent imports.
Import Statement
import_stmt ::= "import" string_literal [ "as" identifier ]
The import statement loads and executes a Lattice source file. The path
is relative to the importing file's directory. The imported module's exports are
bound as a map to the given alias (or the module's basename if no alias is provided).
// Import the entire module import "./utils.lat" as utils utils.helper() // Without alias, uses filename import "./math.lat"
Selective Import
selective_import ::= "import" "{" import_list "}" "from" string_literal import_list ::= identifier { "," identifier }
The import { ... } from form selectively imports named exports from a module
directly into the current scope.
// Import specific names import { sin, cos, PI } from "./math.lat" // Multiple selective imports import { format, pad_left } from "./formatting.lat"
Exports
All top-level bindings and item declarations in a module are exported automatically. There is no explicit export syntax. Functions, structs, enums, and top-level variables are all accessible to the importer.
Module Caching
Each module is executed at most once. Subsequent imports of the same module (resolved by file path) return the cached exports without re-executing the module body. This prevents duplicate side effects and enables circular dependency handling.
Path Resolution
Module paths are resolved relative to the directory of the importing file. The
.lat extension is required in the path string. Absolute paths are
also supported.
// Relative to current file import "./lib/helpers.lat" as helpers // Parent directory import { Point, Color } from "../shared/types.lat"
require()
The require() built-in function provides an alternative way to load modules
at runtime. It takes a path string and returns the module's exports as a map.
let mod = require("./plugin.lat") mod.get("init")()
Lattice