RFD-0010 — Module system and standpoints
Question
How are Argon source files organized into modules, and how do standpoints (the language’s mechanism for perspectival modeling) integrate with the module system?
Decision
Module organization follows Rust conventions:
- Every
.arfile is a module. The module’s name is the file stem; the module path is the relative directory path. - The package’s entry file is
prelude.arat the package root. The entry file resolves aspkg::preludeand acts as the package-module primary file. - Imports use Rust-style
use vocab::pathsyntax. There is no implicit prelude (RFD-0014); every name visible in a module has a correspondinguseline or fully-qualified path. - Default visibility is module-internal (file-scoped). The
pubkeyword promotes a declaration to package-public visibility. Two-tier visibility (RFD-0011) — no fine-grained access modifiers. - Module configuration splits across two scopes: package-level structure (
standpoints { },defeats { }, etc. inox.toml) and module-level locals.
Standpoints are first-class. A standpoint is a perspective on the knowledge base — a specific viewpoint under which facts may hold or not. Standpoints declare in a project-level partial-order lattice; bridge rules and standpoint compositions follow the lattice. Standpoint scoping integrates with per-tenant overlays (RFD-0020): each tenant carries a primary standpoint sourced from their tenant config.
use foo::bar::Sym; parses as single-symbol Named import (Rust-style), not as a glob or module import.
Rationale
Filesystem hierarchy is the module hierarchy. Forcing the language’s namespace structure to match the filesystem layout removes a degree of freedom that produces drift. A reader looking at ufo/properties/identity.ar knows the qualified path is ufo::properties::identity without having to read the file.
No implicit prelude. Auto-imported names are convenience that compounds confusion: which module is Nat from? Adding the explicit use line takes one second when writing and saves an hour when debugging. Bare primitive names produce diagnostic OE0101 with a contextual hint pointing at the appropriate std::math::* import.
Standpoints as a lattice, not a flag. Real perspectival modeling has multiple cross-cutting viewpoints (legal vs. accounting, insurer vs. policyholder, federal vs. state). A standpoint flag would have collapsed all these into one axis. The lattice admits multiple orthogonal viewpoints with explicit composition.
Module-internal default reduces accidental coupling. Most declarations should not be public. Defaulting to module-internal means that promoting something to pub is a deliberate act, and the declaration’s visibility is visible in its declaration line.
Consequences
- File names map directly to module names; rename a file → rename the module.
prelude.aris the convention; library entry + package-module primary file in one.- Re-exports use
pub use. Re-export resolution is a fixpoint overlocal ∪ re_exportsin the elaborator’s import-resolution pass; chain depth is bounded bymodule_count + 1(cycles surface asOE0903). - Package-name canonicalization: manifests admit hyphens or underscores; canonical form is underscored; transform at parse.
- Standpoints integrate with the kernel’s bitemporal event log (RFD-0021) as discriminator axes (
standpoint_id,module_id,fork_id).