Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Split a program into modules

An import names a source file without executing it. Modules contain declarations and imports; execution starts at the application’s main. Names are private to their module unless marked pub.

Save this companion file as geometry.plenty:

pub class Point:
    pub x: i64
    pub y: i64

    pub def squared_length(self) -> Result[i64, OverflowError[i64]]:
        Ok(self.x * self.x + self.y * self.y)

pub def make_point() -> Point:
    Point(3, 4)

Save the application beside it, for example as main.plenty:

import geometry
from geometry import Point as Position

def main() -> Result[(), IoError | OverflowError[i64]]:
    point: Position = geometry.make_point()
    print(point.squared_length()?)?
    print(point.x)?
    Ok(())
25
3

import geometry makes declarations reachable through geometry.Name. from geometry import Point as Position binds just that type under a local name. You can also write import geometry as geo, then use geo.Point. Aliases refer to the same declaration. Two modules may each define Point; those are distinct types.

Imports are absolute. import tools.geometry reads tools/geometry.plenty under the source root. Directories provide namespaces and need no __init__ file. The root defaults to the entry file’s directory. If the entry file is deeper in the tree, select the root explicitly:

plenty --module-root src src/app/main.plenty
plenty --module-root src --compile src/app/main.plenty -o app
plenty --module-root src --check-module src/tools/geometry.plenty

--check checks a complete application and requires main. --check-module checks a library and its imports without that requirement.