Modules
File imports
import "util.nv" binds a sibling source file as module util. The
path is relative to the importing file, the module’s name is the file
stem, and its members are reached with the dot: util.Double(3),
util.Pair{...}. Diamond imports load once; an import cycle is a
compile error naming the cycle.
// util.nv
fn Double(n int) int {
return n * 2
}
// main.nv
import "util.nv"
fn main() {
print(util.Double(21)) // 42
}
Modules are namespaces, not values: u := util does not compile, and
module functions are called directly.
Visibility: the capital letter
A module’s top-level name is exported when it starts with a capital letter; otherwise it is private to its file. No keywords, Go’s rule, and it applies to struct fields too:
- calling an unexported function through a module is a compile error;
- a struct with any unexported field cannot be constructed outside its module at all, because literals must supply every field. That is the constructor pattern: keep one field lowercase and exports control creation.
Inside the defining file, everything is reachable; the rule binds at module boundaries only.
Test files are inside the boundary
A file named util_test.nv sees util.nv’s unexported names through
the ordinary qualified syntax, exactly like Go’s same-package tests.
The testing chapter covers the rest.
The three imports
import "file" // standard library (math, error, file, ctx, gpu, http, test)
import "util.nv" // another nevla file, namespaced by stem
import py "torch" // a Python module through the bridge
Standard library modules are documented in
the reference. Py imports are governed by the project
manifest: inside a project, import py of an undeclared package is a
compile error (the py bridge).