Functions
Basic Functions
fn square(x: i64) -> i64 {
ret x * x
}
fn greet(name: &i8) {
print("Hello, ")
print(name)
print("!\n")
}Functions are defined with fn. Parameters require type annotations. The return type follows ->. Functions without a return type return void.
Multiple Parameters
fn clamp(val: i64, lo: i64, hi: i64) -> i64 {
if val < lo { ret lo }
if val > hi { ret hi }
ret val
}Jda supports up to 6 parameters per function (matching the x86-64 calling convention registers).
Closures
fn make_adder(n: i64) -> fn(i64) -> i64 {
let captured = n
ret fn(x: i64) -> i64 {
ret x + captured
}
}
fn main() -> i64 {
let add5 = make_adder(5)
print_i64(add5(10)) // 15
ret 0
}Closures capture variables from their enclosing scope. They must capture at least one variable.
Generic Functions
fn identity<T>(x: T) -> T {
ret x
}
fn max<T>(a: T, b: T) -> T {
if a > b { ret a }
ret b
}
fn swap<T>(a: &T, b: &T) {
let tmp = *a
*a = *b
*b = tmp
}The compiler generates specialized versions at each call site (monomorphization). max<i64> becomes max_i64, max<i32> becomes max_i32.
Const Generics
Functions can accept compile-time integer parameters:
fn zeros<const N>() -> [i64; N] {
let arr: [i64; N]
for i in range(N) { arr[i] = 0 }
ret arr
}
fn dot_product<const N>(a: [i64; N], b: [i64; N]) -> i64 {
let sum = 0
for i in range(N) {
sum += a[i] * b[i]
}
ret sum
}Defer
Deferred function calls execute when the enclosing function returns:
fn read_file(path: &i8) -> &i8 {
let fd = file_open(path, 0)
defer file_close(fd)
// file_close(fd) runs after ret
ret file_read_all(fd)
}Multiple defers execute in LIFO (last-in, first-out) order. See Error Handling for more patterns.
Built-in Functions
| Function | Description |
|---|---|
print(s) | Print string to stdout |
print_i64(n) | Print integer to stdout |
print_f64(n) | Print float to stdout |
panic(msg) | Print message and abort |
alloc_pages(n) | Allocate n memory pages |
assert(cond, msg) | Assert condition or panic |