Top-level Atoll declarations are public by default. Add private when a
declaration is an implementation detail.
struct Booking {
id: int
}
private fn storage_key(id: int): string {
return "booking:$id"
}Booking may be imported. storage_key may be used only in the file that
declares it.
Visibility is checked after project-wide declaration collection, so a hidden name is not made accessible merely because the compiler knows it exists.
File privacy
The current compiler enforces private at the file boundary. A private
declaration is hidden from:
- files in other modules;
- sibling files in the same module;
- named imports and module-namespace member lookup.
This is intentionally stricter than the old design text that described directory-wide privacy.
A sibling that needs the behavior cannot import the private declaration or use it through the shared module scope. Move deliberately shared functionality into a public declaration with a stable contract instead of relying on physical proximity.
Supported declarations
The modifier applies to top-level functions, structs, enums, errors, constants, aliases, and other declaration forms accepted by the parser.
private const BLOCK_SIZE: int = 4096
private type StorageId = int
private error DecodeError {
InvalidHeader
}Place private with the declaration modifiers and decorators:
@inline
private fn decode_tag(value: byte): int {
return value as int
}private in this chapter concerns top-level declaration reachability. It does
not introduce class-style protected visibility or a package-private tier.
Explicit public declarations
pub is accepted as an explicit public modifier:
pub fn open_booking(id: int): Booking {
return load_booking(id)
}Because public is the default, reserve pub for generated code, style rules,
or files where explicit export markers genuinely improve review. Mixing
implicit and explicit public style arbitrarily adds noise.
pub and the default public state are semantically equivalent. Neither grants
host capabilities or bypasses an imported dependency’s own visibility.
API design
Visibility answers whether a name is reachable; it does not freeze its contract. Public APIs should still use explicit parameter, result, and error types. Keep helpers private until another file actually needs them, then move shared helpers into a deliberately named public module rather than exporting an entire implementation surface.
Public declarations also become part of module-name collision checking across sibling files. Choose names at module scope, not just within the source file.
Refactoring
Moving a public declaration between files in the same directory preserves its module import path. Moving it to another directory changes that path. Making a public declaration private can break both external imports and same-module sibling references.
Before tightening visibility, search named imports, namespace member access, and unqualified same-module uses. The compiler will diagnose unresolved uses, but the refactoring is easier to review when those consumers move in the same change.