Functions
Basic functions
fn add(a: i64, b: i64) -> i64 {
return a + b;
}Default parameters
fn greet(name: string, loud: bool = false) {
if (loud) {
io.println("HELLO, " + name + "!");
} else {
io.println("Hello, " + name);
}
}
greet("world"); // uses default
greet("world", true); // overridesDefault parameters must be trailing — once a parameter has a default, all subsequent parameters must also have defaults.
Named arguments
Named arguments allow you to skip middle defaults and improve readability at call sites:
fn create_window(title: string, width: i64 = 800, height: i64 = 600, vsync: bool = true) -> Window { }
create_window("My App"); // all defaults
create_window("My App", 1024, 768); // positional
create_window("My App", height: 400); // skip width, keep its default
create_window("My App", vsync: false); // skip width and height
create_window("My App", height: 400, width: 1024); // named, any orderRules:
- Positional arguments come first. Once a named argument appears, all subsequent arguments must also be named.
- Named arguments can be in any order. They are matched by name, not position.
- Only parameters with defaults can be skipped. Required parameters must always be provided (positionally or by name).
- Naming is never required. Pure positional calling always works.
- Duplicate parameters are an error. Providing the same parameter both positionally and by name fails at compile time.
fn connect(host: string, port: i64 = 443, timeout_ms: i64 = 5000, tls: bool = true) -> Connection or NetError { }
connect("api.example.com", tls: false, timeout_ms: 1000); // host positional, rest named
connect(host: "localhost"); // all named, port/timeout/tls default
connect(port: 443); // ERROR: host is requiredNamed arguments work with methods (self/*self is never named — it’s passed via dot notation):
fn Buffer.resize(*self, new_cap: i64 = 4096, zero_fill: bool = true) { }
buf.resize(); // both defaults
buf.resize(8192); // positional
buf.resize(zero_fill: false); // named, skip new_capNamed arguments are not available through function pointers — pointers erase parameter names.
Methods
Use Type.name syntax to declare a method on a struct:
struct Vec2 { x: f64; y: f64; }
fn Vec2.length(*self) -> f64 {
return math.sqrt(self.x * self.x + self.y * self.y);
}
let v = Vec2 { x: 3.0, y: 4.0 };
let len = v.length(); // 5.0The first parameter is self (by value) or *self (by pointer).
Visibility
pub fn api_function() -> i64 { return 42; }
fn internal_helper() { }pub makes a function visible to importers. Without it, the function is module-private.
Multiple functions can be exported together with a pub {} block:
pub {
fn init() { ... }
fn update() { ... }
fn shutdown() { ... }
}External functions (C FFI)
@link("kernel32");
extern fn GetTickCount() -> u32;Calls a C function using the platform ABI. The compiler emits an ABI trampoline automatically.
Exported functions
@export
pub fn tape_init() -> i32 {
return 0;
}Makes a tape function callable from C. The function uses the platform calling convention at the boundary.
Operator overloading
Define methods named op_* to overload operators on structs:
struct Vec2 { x: f64; y: f64; }
// Arithmetic
fn Vec2.op_add(self, other: Vec2) -> Vec2 { return Vec2 { x: self.x + other.x, y: self.y + other.y }; }
fn Vec2.op_sub(self, other: Vec2) -> Vec2 { return Vec2 { x: self.x - other.x, y: self.y - other.y }; }
fn Vec2.op_mul(self, other: Vec2) -> Vec2 { return Vec2 { x: self.x * other.x, y: self.y * other.y }; }
fn Vec2.op_div(self, other: Vec2) -> Vec2 { return Vec2 { x: self.x / other.x, y: self.y / other.y }; }
fn Vec2.op_mod(self, other: Vec2) -> Vec2 { return Vec2 { x: self.x % other.x, y: self.y % other.y }; }
// Unary negation
fn Vec2.op_neg(self) -> Vec2 { return Vec2 { x: -self.x, y: -self.y }; }
// Comparison
fn Vec2.op_eq(self, other: Vec2) -> bool { return self.x == other.x && self.y == other.y; }
fn Vec2.op_lt(self, other: Vec2) -> bool { return self.x < other.x; }
fn Vec2.op_lte(self, other: Vec2) -> bool { return self.x <= other.x; }
fn Vec2.op_gt(self, other: Vec2) -> bool { return self.x > other.x; }
fn Vec2.op_gte(self, other: Vec2) -> bool { return self.x >= other.x; }Usage:
let a = Vec2 { x: 1.0, y: 2.0 };
let b = Vec2 { x: 3.0, y: 4.0 };
let c = a + b; // op_add
let d = -a; // op_neg
let eq = a == b; // op_eq
let ne = a != b; // auto-derived from op_eq!= is automatically derived from op_eq.
Last modified: