Declarations are private to their module. The export block makes them public.
An internal helper file
internal_value #= 42
The child root uses it directly
import @utils {internal_value}
export:
import @utils {internal_value}
;
Same-module imports see everything. No export block needed.
Other modules need the export block
import @components {internal_value}
Now the parent module can import internal_value through the @components public surface. It cannot bypass that surface with @components/utils.
Module visibility controls which declarations cross a module boundary. Normal declarations are private to their module. The export: block marks what other modules can see.
Same-module internal visibility
Files within the same module can import each other's declarations directly. A module is defined by its root directory. All .moth files in that directory (and its subdirectories that do not have their own root) belong to the same module.
Given this topology:
src/
├── @site.moth
└── components/
├── @api.moth
└── utils.moth
utils.moth and @api.moth belong to the same components child module. Same-module imports can see private declarations.
Internal helper:
internal_value #= 42
internal_fn || -> String:
return "internal"
;
Child root:
import @utils {
internal_value,
internal_fn,
}
export:
import @utils {
internal_value,
}
;
Same-module imports bypass the public-surface boundary. The importing file sees all declarations in the target file.
Cross-module public boundary
A different module can only access declarations marked public by the module root's export: block. Cross-module imports cannot bypass the public API.
import @components {
internal_value,
}
The parent module sees only the components child module's export: surface. It cannot bypass that boundary with import @components/utils {internal_value}. The @components/utils path cannot bypass the child facade.
Without the root export block, the public import is rejected with MOTH-IMPORT-0011.
Normal modules are not source packages
An @*.moth normal module is not a source package. Use +package.moth when the example intends to teach a scoped package. See Project-local packages for the support-package contract.
Root-private declarations
Declarations in the module root file outside the export: block are private to the root. They are not available to other modules even through the public surface.
Direct root import rejection
Direct imports of normal module-root files are rejected. Import the module through its directory path, not through the root filename.
Runtime top-level bindings not importable
Runtime top-level bindings are start-body code. They are not importable declarations. Only compile-time constants, functions, structs, choices, type aliases and traits are importable.
Receiver method visibility
Receiver methods are visible through a module's public surface when the module exports the receiver type's source surface. A type alias in the export block does not automatically re-export private implementation methods. Export the receiver type's source surface or a wrapper explicitly.
Import cycles
Circular imports between files in the same module are accepted when the declarations resolve in dependency order. Circular constant dependencies are rejected with MOTH-RULE-0033.
No public access through filesystem tricks
There is no way to bypass the module public-surface boundary by choosing a different import path. All cross-module imports go through the same resolution and visibility check.
Related concepts