Modules

A program can be split into files. import loads another file, named relative to the importing file and without the .cz extension:

// main.cz
import "shapes"

print(area(square(3)))
// shapes.cz
pub struct Square do
    int side
end

pub func square(int side) Square do
    return Square(side)
end

pub func area(Square s) int do
    return s.side * s.side
end

A name may include directories, as in import "lib/text" or import "../common", but it must be relative: absolute paths and drive letters are rejected. Imports are top-level only. Each file is loaded once, however many files import it, so imports may repeat or form cycles. Declarations can be used in any order. Only the main file, the one given to cuarzo, may contain top-level statements; imported files hold declarations and imports.

Public and private names

A declaration marked pub can be used by the files that import its file; any other declaration is private to its file. A file sees its own functions, structs, enums, interfaces, and constants, and the public ones of the files it imports. Using a private name of another file is an error that says so, and using a name of a file that is not imported is an error that names the file. Private names never clash, so two files may each have a private helper; two public names that one file sees together cannot be the same. Methods belong to their type, wherever it is used.

An import does not pass the imported file's names on: a file that imports a, which imports b, sees a's public names but not b's. pub import passes them on, so a module can gather others under one name:

// geometry/index.cz
pub import "shapes"          // geometry/shapes.cz
pub import "angles"

pub func describe(Square s) str do
    return f"a square of side {s.side}"
end

A folder with an index.cz is a module too: when there is no geometry.cz, import "geometry" loads geometry/index.cz.

import "x" as name gives the imported file a name instead. Its declarations are then reached only through that name, so they never clash with the importer's:

import "std/term" as term
import "shapes" as shapes

// std/term has a `table` too, but here it is `term.table`.
func table() str do
    return "my table"
end

shapes.Square s = shapes.square(3)
print(shapes.area(s), table())
print(term.paint("done", "green"))

name.x reaches the public names of the file and those it passes on with pub import. It works for functions, constants, structs, and enums, in expressions, in types such as shapes.Square[] or Option[shapes.Square], and in match patterns such as when shapes.Kind.ROUND. Two modules imported with as may declare the same names. The name given cannot be used for a variable or parameter in that file, and two imports in one file cannot share a name.

A name that starts with std/ imports a module of the standard library, such as import "std/term". The compiler carries these modules, so they work from any directory. A file that imports a module and wants its names imports it itself, as with any other module.