Imports and Modules

OxigenLang has a module system that lets you organize code across files and use the standard library. The introduce keyword (or its shorthand intro) brings modules into scope.

#Standard Library Imports

Use a bare module name to import from the standard library:

Oxigen
introduce math
println(math.sqrt(16))
println(math.abs(-5))

This creates a namespace — you access the module's functions through the module name with dot notation.

#Selective Imports

To import specific functions directly into your scope, use curly braces and from:

Oxigen
introduce {sqrt, abs} from math
println(sqrt(16))
println(abs(-5))

Selective imports don't require the module prefix.

#Local File Imports

Use a dot prefix to import from local .oxi files relative to the current file:

Oxigen
// Import from ./helpers.oxi (same directory)
introduce .helpers
helpers.my_function()

// Selective import from local file
introduce {my_function} from .helpers
my_function()

// Import from ../utils/format.oxi (parent directory)
introduce ..utils.format
  • . means the current file's directory
  • .. means one directory up
  • Additional dots go further up (e.g., ... = two directories up)
  • Dots between names are path separators

#The intro Shorthand

intro is an alias for introduce — they are identical:

Oxigen
intro math
intro {split, join} from strings
intro .helpers

#Module Behavior

#Namespacing

Whole-module imports create a namespace object. You access members with dot notation:

Oxigen
introduce math
introduce strings

println(math.pow(2, 10))
println(strings.upper("hello"))

#Exports

Top-level bindings (functions, variables, structs, and patterns) are exported by default — public unless you say otherwise. There is no export list; the exception is marked at the declaration with hide.

Use top-level definitions for reusable module APIs, and put script-only work inside main. The main block is skipped when the file is imported with introduce.

#hide — module-private functions

A top-level fun marked hide stays callable inside its own file and is refused across the module boundary:

Oxigen
// text.oxi
hide fun __normalize(s <str>) { strings.trim(strings.lower(s)) }

fun matches(a <str>, b <str>) { __normalize(a) == __normalize(b) }
Oxigen
introduce .text

text.matches(" Ada ", "ada")   // True — the public face
text.__normalize(" Ada ")      // error: '__normalize' is hidden inside module './text'

Both routes in are closed, and the error names the reason rather than pretending the function does not exist:

Oxigen
introduce {__normalize} from .text
// error: '__normalize' is hidden inside module './text'
//   hint: it is declared `hide fun` and cannot be imported

hide applies to top-level functions only — hide x <int> = 1 is a parse error. For struct fields, hide goes inside the struct body; see structs.md.

The stdlib uses it: array.oxi marks _min_index_by and _remove_at hidden, since they are the selection sort behind sort_by rather than part of the module's API.

Oxigen
// mylib.oxi
fun greet(name) { "Hello, {name}!" }
PI := 3.14159
Oxigen
// main.oxi
introduce .mylib

main {
    println(mylib.greet("World"))
    println(mylib.PI)
}

#Module Caching

Each module file is evaluated only once. If multiple files import the same module, they share the same module object. This means module-level state is shared.

#Circular Import Detection

If file A imports file B which imports file A, OxigenLang will produce a clear error:

Error: circular import detected: /path/to/file.oxi

Restructure your code to avoid circular dependencies.

#Standard Library Modules

OxigenLang ships with the following standard library modules:

ModuleDescription
mathMath functions (abs, sqrt, pow, floor, ceil, etc.)
stringsString manipulation (split, join, trim, upper, etc.)
arrayArray operations (map, filter, reduce, sort, etc.)
setsSet algebra (union, intersection, difference, etc.)
ioFile I/O (read_file, write_file, etc.)
osOS interaction (exec, env vars, directories, etc.)
pathFile path manipulation and containment checks
timeTimestamps, sleep, elapsed time measurement
datetimeUTC calendar dates: format, parse, components
randomRandom number generation
regexRegular expressions (Rust regex syntax)
jsonJSON parsing, serialization, dotted-path access, and merging
tomlTOML parsing, serialization, dotted-path access, and merging
encodingBase64, hex, and URL percent-encoding
hashSHA-256, SHA-1, MD5 hex digests
netHTTP client, streaming HTTP, TCP and UDP sockets
apiHTTP server: routing, JSON responses, accept loop
resultHelpers for the Error || Value system
testexpect(...) matchers used by oxigen test
ansiTerminal colour, modifiers, cursor control
envLoad a .env file into a map
parse_argsCommand-line flag parsing

See the Standard Library Reference for full details on each module.

#Examples

#Using multiple modules together

Oxigen
introduce json
introduce net
introduce io

// Fetch JSON from an API
resp := net.get("https://api.example.com/data")
data := json.parse(resp["body"])

// Save to file
io.write_file("data.json", json.stringify(data))

#Building a utility with local imports

Oxigen
// utils/format.oxi
fun pad_left(s, width, ch) {
    result := s
    repeat when len(result) < width {
        result := str(ch) + result
    }
    result
}
Oxigen
// main.oxi
introduce .utils.format

main {
    println(format.pad_left("42", 5, "0"))
}