Modules
A Yona module is a named collection of functions and types that compiles to a native object file. Modules are top-level declarations, not expressions — they cannot be passed around, returned, or stored in data structures. One file, one module.
Declaring a module
Section titled “Declaring a module”A module file starts with module Pkg\Name and ends at end-of-file —
there is no closing end keyword. The name is a fully qualified name (FQN)
with backslash-separated package segments:
module Data\Geometry
export area, perimeterexport type Shape
type Shape = Circle Float | Rect Float Float
area shape = case shape of Circle r -> 3.14159265 * r * r Rect w h -> w * hend
perimeter shape = case shape of Circle r -> 2.0 * 3.14159265 * r Rect w h -> 2.0 * (w + h)end
# Private helper — not exported, invisible to importerssquare x = x * xEverything after the exports is ordinary Yona: type declarations and
function definitions. Anything not listed in an export statement is
private to the module.
Exports
Section titled “Exports”export is a standalone statement and may appear any number of times, each
handling one group of names:
export area, perimeter # functionsexport type Shape # a type AND all of its constructorsexport scale from Data\Xform # re-export from another moduleThe three forms, precisely:
- Functions:
export f, gmakesfandgcallable by importers. - Types:
export type Shapeexports the type together with all its constructors (Circle,Rect), so importers can construct values and pattern-match on them. - Re-exports:
export f, g from Other\Modrepublishes names defined in another module as if they were defined here. Importers depend only on the re-exporting module. The re-exporting module may also use those names in its own definitions:
module Std\Convenience
export add, mul from Std\Arithexport double
double x = add x x # re-exported names are usable locallyImports are expressions
Section titled “Imports are expressions”import … in body brings names into scope for the body expression only
— it is scoped like let, not a file-level statement. This means imports
can appear anywhere an expression can, and their scope is exactly as large
as you make it.
Selective import
Section titled “Selective import”import area from Data\Geometry inarea (Circle 1.0)# => 3.14159265Aliased import
Section titled “Aliased import”Rename on import with as — useful for avoiding clashes or shortening
names:
import area as shapeArea from Data\Geometry inshapeArea (Rect 2.0 3.0)# => 6.0Whole-module import
Section titled “Whole-module import”Importing just the module name brings all of its exports into scope:
import Data\Geometry inarea (Circle 1.0) + perimeter (Rect 2.0 3.0)Prefer selective imports in anything but throwaway code; they document where each name comes from.
Multi-module imports
Section titled “Multi-module imports”One import can pull from several modules, comma-separated. This is the
idiomatic form — do not nest import expressions:
import area from Data\Geometry, println from Std\IOindo println "computing" area (Circle 1.0)endFully qualified calls
Section titled “Fully qualified calls”Pkg\Mod::func calls an exported function directly, with no import at
all. The compiler auto-loads the module’s interface:
Std\List::map (\x -> x + 1) [1, 2, 3]# => [2, 3, 4]FQN calls suit one-off uses; switch to an import when a module is used more than a couple of times in the same expression.
How yonac compiles a module
Section titled “How yonac compiles a module”Compiling a module file produces two artifacts:
yonac -o Geometry.o Data/Geometry.yona# produces Geometry.o (native object) + Data/Geometry.yonai (interface)- The object file (
.o) contains native code with C-ABI exports. Names are mangled predictably —Data\Geometry::areabecomesyona_Data_Geometry__area— so Yona modules link with C (and anything with a C FFI) through the ordinary system linker. - The interface file (
.yonai) is a text file describing the exported functions’ signatures, ADT definitions, traits, and inferred effect rows. It is what makes cross-module calls type-checked: when you import a module, the compiler reads its.yonai, not its source. Exported functions also embed their source text in the interface, so generic functions can be re-specialized at call sites whose types differ from the pre-compiled signature (cross-module monomorphization).
When resolving import Data\Geometry, the compiler looks for
Data/Geometry.yonai in the -I search paths, then next to the input
file, then in the current directory:
yonac -I ./lib -I "$YONA_HOME/lib" -o program main.yonaModules must be compiled in dependency order — circular module dependencies are not supported.
For the interface file format, borrow inference metadata, and the details of cross-module generics, see Modules and interfaces.
A complete two-file example
Section titled “A complete two-file example”Data/Counter.yona:
module Data\Counter
export type Counterexport make, bump, value
type Counter = Counter Int
make = Counter 0bump c = case c of Counter n -> Counter (n + 1) endvalue c = case c of Counter n -> n endmain.yona:
import make, bump, value from Data\Counter invalue (bump (bump make))# => 2Build and run:
yonac -o Counter.o Data/Counter.yonayonac -I . -o main main.yona./main # exit code 2The exported Counter constructor is available to main.yona because
export type Counter exports the type with its constructors; bump’s
pattern match on Counter n in an importing module would work the same
way.