Module state (how-to)¶
This guide shows how to solve a concrete problem with static: keep live module-owned state and optionally share it across files.
If you need the exact rules, see: Static storage (reference).
Task: keep a module-local counter¶
static counter: int = 0
pub def next_counter() -> int:
counter += 1
return counter
Use this when the state belongs to the module itself and callers should access it through functions.
Task: export shared state across files¶
- Declare the shared storage with
pub static. - Update it through normal functions in the exporting module.
- Import the live value from another file.
This example shares live runtime state across module boundaries with pub static:
pub static hits: int = 0
pub def record_hit() -> None:
hits += 1
from counters import hits, record_hit
def main() -> None:
record_hit()
record_hit()
println(hits)
This prints 2.
Because hits is live module storage, the import sees the updated value after the function call.
Task: share a mutable collection¶
- Export the collection with
pub static. - Mutate it through helper functions.
- Import it only if callers really need the live collection itself.
pub static names: list[str] = []
pub def register(name: str) -> None:
names.append(name)
Elsewhere:
from registry import names, register
def main() -> None:
register("Ada")
register("Linus")
println(len(names))
Use this only when the shared collection itself is part of the module’s public surface.
Task: keep mutation behind functions¶
Prefer this shape when callers only need behavior, not direct access to the storage:
static names: list[str] = []
pub def register(name: str) -> None:
names.append(name)
pub def registered_count() -> int:
return len(names)
That keeps mutation rules in one place and prevents other modules from depending on too much internal detail.
Expose pub static only when sharing the actual live state is part of the API.
Avoid these mistakes¶
Mistake: using const for runtime state¶
const request_count: int = 0
This is wrong if the value changes while the program runs: use static.
Mistake: omitting the type annotation¶
static request_count = 0
This is rejected. static always needs an explicit type.
Mistake: rebinding an imported static¶
from stats import request_count
def reset() -> None:
request_count = 0
This is rejected because the imported name still refers to the exporter’s storage.
Pick the right tool¶
- Use
constfor fixed compile-time data. - Use
staticfor module-owned runtime state. - Use local variables and return values for ordinary flow through your program.