Functions
Functions are first-class values — you can assign them to variables, pass them as arguments, and return them from other functions.
Named functions
The most common way to define a function. Return type and parameter types are optional:
fn int add(int a, int b) {
return a + b
}
fn void greet(string name) {
out "Hello, {name}!"
}
fn bool isAdult(int age) {
return age >= 18
}
out add(3, 7) // → 10
out isAdult(16) // → false
greet("Sergio") // → Hello, Sergio!Arrow functions
Arrow functions are great for short callbacks. The return type goes before the parentheses:
let double = int (int n) => {
return n * 2
}
let shout = string (string s) => {
return s.toUpperCase() + "!"
}
out double(5) // → 10
out shout("hello") // → HELLO!Anonymous functions
Functions without a name — useful when you need to pass logic around:
let run = fn void () {
out "running..."
}
run() // → running...Default parameters
Parameters can have default values. If the caller doesn't pass the argument, the default is used. Default parameters must come after required ones:
fn string greet(string name = "World") {
return "Hello, {name}!"
}
out greet() // → Hello, World!
out greet("Sergio") // → Hello, Sergio!
fn int add(int a, int b = 10) {
return a + b
}
out add(5) // → 15 (b defaults to 10)
out add(5, 3) // → 8 (b supplied)Recursion
Functions can call themselves. The call stack is tracked and shown clearly if an error occurs:
fn int factorial(int n) {
if (n <= 1) { return 1 }
return n * factorial(n - 1)
}
out factorial(6) // → 720
fn int fibonacci(int n) {
if (n <= 1) { return n }
return fibonacci(n - 1) + fibonacci(n - 2)
}
out fibonacci(10) // → 55Functions as values
Functions can be stored in variables and passed as arguments:
fn int double(int n) { return n * 2 }
fn int square(int n) { return n * n }
let op = double // store a function
out op(5) // → 10
op = square // swap it out
out op(5) // → 25
// Pass as argument
fn int applyTwice(fn int op, int x) {
return op(op(x))
}
out applyTwice(double, 3) // → 12 (double(double(3)) = double(6) = 12)Closures
Functions capture variables from the scope they're defined in:
let multiplier = 3
let nums = [1, 2, 3, 4]
// The lambda captures 'multiplier' from outside
let tripled = nums.map(x => x * multiplier)
out tripled // → [3, 6, 9, 12]
// Making a counter with closure
fn make_counter() {
let count = 0
return fn void () {
count = count + 1
out count
}
}
let counter = make_counter()
counter() // → 1
counter() // → 2
counter() // → 3Lambda syntax (for callbacks)
When passing functions to map, filter, reduce, or similar, use the short lambda syntax:
let nums = [1, 2, 3, 4, 5]
// Single parameter — no parentheses needed
nums.map(x => x * 2)
// Two parameters (value + index)
nums.map((x, i) => "{i}: {x}")
// Multi-line lambda
nums.filter(x => {
let isEven = x % 2 == 0
return isEven
})
// Reduce — accumulator + current value
nums.reduce(0, (acc, x) => acc + x) // → 15