THE JOA LANGUAGE

Functions

Define Joa functions, pass arguments, return values, write recursive calls, and capture state with closures.

Declaration

fn function_name(param1, param2) {
    // body
    return value
}
  • Parameters are positional; no default values.
  • return exits the function and optionally produces a value.
  • A function without return returns null.
  • Functions are values — they can be stored in variables and passed as arguments.
fn add(a, b) {
    return a + b
}

let result = add(10, 20)
print(result)   // 30

Recursion

fn factorial(n) {
    if n <= 1 {
        return 1
    }
    return n * factorial(n - 1)
}

print(factorial(6))   // 720

Functions as Values

fn double(x) {
    return x * 2
}

let transform = double
print(transform(7))   // 14

Closures and Nested Functions

Functions in Joa use lexical scoping — they capture the environment at the point of their definition. This makes closures possible:

fn make_counter(start) {
    let count = start

    fn increment() {
        count += 1
        return count
    }

    return increment
}

let counter = make_counter(0)
print(counter())   // 1
print(counter())   // 2
print(counter())   // 3

Each call to make_counter() creates an independent closure with its own count variable. The inner function increment captures count from its enclosing scope and can both read and update it.

Higher-Order Functions

fn apply(f, value) {
    return f(value)
}

fn square(x) {
    return x ** 2
}

print(apply(square, 5))   // 25.0

Argument Count

Calling a function with the wrong number of arguments raises a Runtime Error with a clear message:

fn greet(name) { return "Hello " + name }
greet()
// ❌ Runtime Error: Function 'greet' expects 1 argument(s), but got 0.
// 💡 Hint: Pass exactly 1 argument(s) to 'greet'.