11. Modules
A Korrin program is one or more modules. Each .kor file is a module; the
import statement (§5.12) loads another module and binds it
as a value. This section is the normative description of loading, module objects,
and the standard library (ADR 0018,
ADR 0019).
11.1 Specifiers and resolution
import_statement = "import" , STRING , [ "as" , NAME ] ;
The string is the specifier. Its first characters decide how it resolves:
./…or../…— a file, resolved relative to the directory of the file containing theimport(not the process's working directory, not the entry file). If the specifier has no extension,.koris appended. A file that does not exist or cannot be read isE0314.- anything else — a built-in module (§11.4), looked up by exact name.
No filesystem is consulted, so
import "math"is always the standard library'smath. An unknown name isE0314.
A relative import requires a file on disk to resolve against. When a program is
run from memory rather than a file (an embedder's in-process call), a relative
import is E0314; built-in imports still work.
11.2 The bound name
import "spec" binds the specifier's final path component, with any extension
removed: import "./a/config" binds config, import "math" binds math.
import "spec" as name binds name instead. If there is no as and the derived
name is not a valid identifier (§1.5), the import is
E0108 and must use as.
The specifier must be a plain string literal; one with interpolation holes is
E0108.
11.3 Module objects
Evaluating an import runs the module once and produces a module object.
type() reports "module".
- Isolation. A module's file runs in its own scope — a fresh global with the
built-in functions and
Error, then the module's own top level. It does not see the importing program's names, and vice versa. - Caching. Loading is cached by canonical path (files) or name (built-ins).
Importing the same module in two places yields the same object;
==on module objects is identity. - Members.
module.namereadsnamefrom the module's top-level bindings. A name that is not bound isE0309. - Privacy. A top-level name beginning with
_is private: reading it through the module object isE0309, even though it is bound. Code within the module uses its own_-names normally.
A module object is not callable (E0302), not indexable
(E0308), and not iterable.
import "math"
print(type(math))
print(math.pi > 3)
# => module
# => true
11.4 The math module
import "math". Numeric helpers and two constants. math is float-flavoured:
sqrt and pow return float; the rounding functions return int.
| Member | Result |
|---|---|
math.sqrt(x) | the square root of x as a float; E0304 if x < 0 |
math.pow(base, exp) | base raised to exp, as a float |
math.floor(x) | the largest int not greater than x; E0304 if it does not fit int |
math.ceil(x) | the smallest int not less than x |
math.round(x) | x rounded to the nearest int, halves away from zero |
math.abs(x) | the absolute value of x, keeping its type (int or float) |
math.min(a, ...) | the smallest of one or more numbers, returned unchanged |
math.max(a, ...) | the largest of one or more numbers, returned unchanged |
math.pi | π, as a float |
math.e | e, as a float |
import "math"
print(math.sqrt(49))
print(math.floor(2.9))
print(math.abs(-7))
print(math.max(3, 8, 1))
# => 7.0
# => 2
# => 7
# => 8
11.5 The io module
import "io". Filesystem access and command-line arguments
(ADR 0020). Every operation that can fail
raises E0316, which try can catch. Paths are used as
given — a relative path is relative to the process's working directory, not the
script's location. There is no sandbox.
| Member | Result |
|---|---|
io.read_file(path) | the file's contents as a str; E0316 if it cannot be read or is not UTF-8 |
io.write_file(path, text) | writes text to path, creating or truncating it; returns nil; E0316 on failure |
io.args() | a list of the command-line arguments after the script name, as strs (empty when run from an embedder) |
import "io"
try:
text = io.read_file("does-not-exist")
except err:
print(err.code)
# => E0316
To read a line from standard input, use the input builtin.
11.6 Cycles
While a module is loading, its path is recorded as "in progress". An import
that resolves to a module already in progress is E0315 — Korrin
never exposes a partially-initialised module. Move the shared definitions into a
third module that both import.
11.7 Compilation errors in imported modules
A lexer, parser, or resolver error in an imported file is reported as a single
E0314 at the import site, carrying the imported module's own
error text. A runtime raise or fault from a module's top level propagates to
the importer as an ordinary exception, catchable with try around the import.