-
Notifications
You must be signed in to change notification settings - Fork 3
Modules
Kairo's module system maps source files and directories to namespaces. Every .k file is a module. A directory containing a module.k entry file is a library. Use the module keyword to declare namespaces within a file, similar to C++ namespace.
See Imports for how to bring names from modules into scope.
Each .k file is automatically a module named after the file (without the .k extension):
project/
main.k <- module "main"
math.k <- module "math"
utils/
module.k <- library entry for "utils"
strings.k <- module "utils::strings"
io.k <- module "utils::io"
internal/
helpers.k <- module "utils::internal::helpers"
Nested files create nested module names via ::. A file at utils/io.k is accessible as the module utils::io.
A directory with a module.k file is a library. The entry file controls what the library exports publicly:
// utils/module.k
pub import strings // re-export utils/strings.k
pub import io // re-export utils/io.k
priv import internal // NOT re-exported (implementation detail)
Imports inside module.k are relative to the directory. pub import strings resolves to utils/strings.k.
Consumers of the library see only the public API:
import utils
utils::strings::trim(" hello ") // from utils/strings.k
utils::io::read_file("data.txt") // from utils/io.k
// utils::internal::... // compile error: not exported
The library entry file is the public face of the library. Use it to re-export submodules, hide internal organization, and present a clean API boundary.
The module keyword declares a namespace within a file. It is equivalent to C++ namespace:
module serialization {
pub fn to_json(data: Config) -> string { ... }
pub fn from_json(input: string) panic -> Config { ... }
priv fn escape_string(s: string) -> string { ... }
}
serialization::to_json(my_config)
A module without a name creates a scope for grouping declarations without introducing a named namespace:
module {
var internal_state: i32 = 0
// not accessible from outside this block
}
Modules can be nested:
module api {
pub module v1 {
pub fn handle_request(req: Request) -> Response { ... }
}
pub module v2 {
pub fn handle_request(req: Request) -> Response { ... }
}
}
api::v1::handle_request(req)
api::v2::handle_request(req)
Modules themselves have visibility. The default is pub:
pub module api {
// accessible to consumers
fn handle_request(req: Request) -> Response { ... }
}
priv module cache {
// only accessible within this file
var store: {string: Data} = {}
}
prot module platform {
// accessible within this file and sibling files in the library
fn detect_os() -> string { ... }
}
| Modifier | Scope |
|---|---|
pub (default) |
Any module that imports this module |
priv |
Current file only |
prot |
Current file and sibling files in the same library subtree |
prot (protected) is scoped to the library subtree, not the immediate directory. Any file anywhere under a library's directory tree can access prot declarations from any other file in that same library. This is analogous to "package-private" in other languages.
A module can be reopened across multiple files to extend its contents:
// encoding.k
pub module codec {
pub fn encode_base64(data: [byte]) -> string { ... }
}
// compression.k
import encoding::codec
pub module codec {
pub fn compress(data: [byte]) -> [byte] { ... }
}
// main.k
import encoding
import compression
encoding::codec::encode_base64(data) // defined in encoding.k
compression::codec::compress(data) // defined in compression.k
- Reopening a module with different visibility than the original is a compile error.
- Reopening may only add new top-level declarations (functions, types, constants). It cannot modify existing declarations or add members to types defined in the original.
- Both declarations must be at file scope (not nested inside other modules).
The :: operator resolves names uniformly across all scoping contexts:
| Context | Example |
|---|---|
| Module access | std::println(...) |
| Library submodule | math::vector::cross_product(...) |
| Class static members | Counter::count |
| Enum variants | Direction::North |
| Nested types | Packet::Header |
| Base class methods | Base::method(self) |
There is no separate syntax for module access vs type member access, all use ::.
std is not automatically imported. It must be imported explicitly:
import std
std::println("hello")
std::create::<i32>(42)
Individual items can be imported selectively:
import std::{println, create}
println("hello")
Core language primitives (i32, string, bool, [T], etc.) and built-in syntax (if, for, match, etc.) are always available without any import. Only standard library functions and types (std::println, std::Error, std::Shared, etc.) require an explicit import.
See Imports for import syntax and the pub import pattern for re-exporting.
Circular imports are a compile error:
// a.k
import b // compile error if b.k imports a
// b.k
import a // circular dependency detected
Break circular dependencies by extracting shared declarations into a third module that both A and B import:
// shared.k
pub fn common_utility() { ... }
// a.k
import shared
// no import b
// b.k
import shared
// no import a
Circular dependencies at the module level reflect circular dependencies in the design, restructuring to break the cycle usually improves the architecture.
All top-level declarations (functions, classes, modules, constants, etc.) default to pub. Use priv to restrict to the current file and prot for library-internal visibility:
pub fn public_api() { ... }
priv fn internal_helper() { ... }
prot fn library_internal() { ... }
pub class Server { ... }
priv class ConnectionPool { ... }
pub eval MAX_CONNECTIONS = 1024
priv static var request_count: i32 = 0
See Imports for how visibility affects what is re-exported via pub import.
This wiki mirrors the language reference at kairolang.org/docs. To edit a page, edit the source at kairo-web/src/content/docs/language changes sync automatically.
Start here: Primitives
1. Fundamentals
2. Functions & Control Flow
3. Types
4. Modules & Metaprogramming
5. Memory & Safety
6. Interop & Concurrency