Functions package reusable Expr code behind a name.
This chapter describes user-defined functions, function calls, return values, parameters, namespaces, and function references.
Built-in functions such as `print()` and numeric helper functions are listed separately in Built-in functions. Object methods are covered in Methods, this, and properties.
Define a function with the `function` keyword, a name, a parameter list, and a block body.
function Add(a, b) { return a + b; }
The function body must be a block.
function Double(value) { value * 2; }
Function declarations define the function. They do not call it.
function Hello() { print('Hello'); } Hello();
Function names use normal Expr identifier rules. Function parameters are positional names.
Call a function by writing its name followed by an argument list in parentheses.
Add(2, 3);
Arguments are evaluated before the function body runs.
result = Add(1 + 2, 3 + 4);
The argument count must match the function parameter count.
function Move(x, y, z) { print(x, y, z); } Move(10, 20, 30); // valid Move(10, 20); // wrong argument count
Empty argument slots and trailing commas are invalid.
Add(, 2); // invalid Add(1, ); // invalid
Parameters are local variable names created for each function call.
function Scale(value, factor) { value * factor; }
Arguments are passed as values.
Changing a parameter name inside the function does not change the caller variable with the same value.
function Change(value) { value = 100; return value; } a = 5; b = Change(a);
After this script, `b` is `100`. The variable `a` is still `5`.
When an object value is passed, the value refers to that object. Object behavior depends on the object type and its methods.
A function call produces a value.
Use `return expression;` to exit the function immediately and return a value.
function Clamp01(value) { if(value < 0) { return 0; }; if(value > 1) { return 1; }; return value; }
If no explicit `return` is used, the function result is the last value produced by the function body.
function Add(a, b) { a + b; } Add(2, 3); // 5
`return;` exits immediately without providing a new explicit value.
function Example(a, b) { a + b; return; }
In this case the function keeps the last produced function value. If no earlier value was produced, the result is `none()`.
function Empty() { return; } Empty().is_none(); // true
`return` is commonly used to stop a function as soon as a special case is handled.
function DivideOrNone(a, b) { if(b == 0) { return none(); }; return a / b; }
Code after a `return` is not evaluated.
function Test() { return 1; return 2; // not evaluated }
Function parameters are local to the call.
function AddOffset(value) { set offset = 10; return value + offset; }
Use `set` for temporary local variables inside functions.
Plain assignment follows normal Expr name-resolution rules. It updates an existing variable if one is found; otherwise it creates a variable in the current root or object context.
count = 0; function Increment() { count += 1; return count; }
For detailed assignment and scope behavior, see Variables and assignment.
Defining a function with the same name replaces the previous user-defined function in the current session or context.
function Mode() { return 'old'; } function Mode() { return 'new'; } Mode(); // 'new'
Use unique, descriptive names for functions that may be included from shared files.
Functions can be defined and called with a namespace prefix.
function MathEx::Clamp(value, low, high) { if(value < low) { return low; }; if(value > high) { return high; }; return value; } MathEx::Clamp(12, 0, 10);
Namespaces are useful for shared libraries and included files.
An included file can also be imported under an alias. See Include system.
When Expr evaluates a call in the form `Name(…)`, it resolves the name in this order:
This means a user-defined function can shadow a built-in function with the same name.
function print(value) { return 'shadowed'; } print('test');
Avoid reusing built-in function names unless shadowing is intentional.
Inside object method context, bare calls may resolve to methods on `this` before root or built-in functions. See Methods, this, and properties.
A function can be used as a value.
function Add(a, b) { return a + b; } f = Add; f.call(2, 3); // 5
Bare identifier value resolution checks variables first, then user-defined function references, then built-in function references.
f = str_spaces; f.call(4); // ' '
Function references are object values. User-defined function references and built-in function references can be passed to APIs that expect callbacks.
button.on_click(this.HandleClick);
Method references are explicit object-member references, such as `this.HandleClick`.
Callback behavior depends on the host object or built-in object that receives the reference.
A function may call itself.
function Factorial(n) { if(n <= 1) { return 1; }; return n * Factorial(n - 1); }
Recursive functions must have a terminating condition.
Expr has evaluation-depth limits. Very deep recursion can fail even when the logic is otherwise correct.
For repeated work, prefer `loop`, `while`, or `for` when a loop is simpler.
A function must be called with the exact number of arguments it declares.
function Add(a, b) { return a + b; } Add(1); // wrong argument count Add(1, 2, 3); // wrong argument count
A function call requires parentheses.
Add; // function reference value Add(); // function call
A function can return `none()` when no value is produced.
function NoValue() { } result = NoValue(); result.is_none(); // true
A user-defined function can hide a built-in function with the same name.
function abs(value) { return value; } abs(-5); // calls user function, not built-in abs
Previous: Control flow
Next: Built-in functions