Modules

Load built-ins and your own `.rn` files with `benutzen`. Every top-level binding is exported: no export keyword.

Rain has two kinds of modules: **built-ins** (math, http, csv, …) and **user modules** (any .rn file on disk).

Load either kind with benutzen "…";. That creates a global whose name is the module stem. Then call into it with ::.

User modules have no special syntax. Write a normal .rn file: top-level var, fun, and class declarations become exports automatically. There is no export keyword and no private-by-default. If it is defined at the top level while the file loads, it is part of the module.

Paths are relative to the **current working directory** when you run ./rain script.rn. Run from the project root so benutzen "lib/model.rn" resolves correctly.

Define a user module

Any top-level `var` or `fun` in a `.rn` file is automatically exported.

lib/greet.rn
var PREFIX = "hello";

fun forUser(name) {
  return PREFIX + ", " + name;
}

Import and call it

Load with `benutzen`, then call exports as `stem::name`.

main.rn
benutzen "lib/greet.rn";

print greet::forUser("world");
print greet::PREFIX;
output
hello, world
hello

Multi-file HTTP server

Split routes, middleware, and config across files: import each with `benutzen`.

server.rn
benutzen "http";
benutzen "str";
benutzen "lib/config.rn";
benutzen "middleware/logger.rn";
benutzen "routes/register.rn";

http::cors(true);
http::use(logger::logger);
register::registerRoutes();

print str::format("server starting on port {0}", config::PORT);
http::listen(config::PORT);

Route module (handler export)

A route file exports handler functions the main server registers.

routes/predict.rn
benutzen "http";
benutzen "json";
benutzen "str";
benutzen "lib/model.rn";

fun predictHandler(req) {
  var data = json::parse(req.body);
  var digit = model::predict(data.pixels);
  return http::jsonResponse(200, "{"digit": " + str::format("{0}", digit) + "}");
}

Importing

How to load modules and call into them with `::`.

SymbolDescriptionExample
benutzen "math"Load a built-in module into global `math`
benutzen "math"; print math::sqrt(9);
benutzen "lib/util.rn"Load a file; global name is the **file stem** (`util`)
benutzen "lib/util.rn"; print util::helper();
module::name()Call an exported function on a loaded module
benutzen "math"; print math::sqrt(16);
module::CONSTRead an exported variable or constant
benutzen "lib/config.rn"; print config::PORT;

How names are chosen

The global name comes from the filename stem, not the folder path.

SymbolDescriptionExample
"routes/predict.rn" → predictDirectory prefix is ignored; only the filename stem matters
benutzen "routes/predict.rn"; predict::predictHandler(req);
"lib/model.rn" → modelNested folders are fine: stem is still just the filename
benutzen "lib/model.rn"; model::predict(pixels);
"math" → mathBuilt-ins use a bare name (no `.rn` suffix)
benutzen "math"; math::zeros(2, 3);

What gets exported

Only top-level bindings become module fields: nothing inside functions.

SymbolDescriptionExample
var x = …Top-level variables are exported as `module::x`
var PORT = 8080;
fun name() { … }Top-level functions are exported as `module::name()`
fun predict(pixels) { … }
class Foo { … }Top-level classes are exported as `module::Foo`
class Point { … }
Top-level codeRuns once on first import (I/O, setup, loading weights)
print "loading weights...";
Locals inside funNot exported: only top-level bindings become module fields
fun f() { var x = 1; }

Built-in modules

Shipped with Rain: load by bare name with `benutzen`.

SymbolDescriptionExample
mathScalars, arrays, matrices, activations, ML helpers
benutzen "math";
csvRead CSV into arrays or matrices
benutzen "csv";
strString search, slice, split, join, format
benutzen "str";
jsonparse / stringify / keys
benutzen "json";
httpServer and HTTP client
benutzen "http";
dbSQLite
benutzen "db";
ioFiles and stdin
benutzen "io";
osPlatform, env, sleep
benutzen "os";
timeDates and clocks
benutzen "time";

Notes