9. Functions
9.1 Function Declaration
function functionName(param1, param2) {
// function body
return value; // optional
}
For functions that consist of a single expression, you may omit the braces and use a semicolon:
function square(x) x*x;
function double(n) -> int n * 2;
This is equivalent to function square(x) { return x*x; }.
The only function keyword is function. fn and def are syntax errors (removed aliases).
You may optionally add informational type hints to parameters and a return type. These are not enforced at interpret-time unless you pass CLI --strict-types. malda compile --mode transpile / publish refuse emit when analysis reports Errors (--lenient-types skips the gate). Known names include Tier 0 primitives, declared class/schema/sum-type names (including those imported from other modules), and built-in host classes. Mismatches on literals, new ClassName(), identifiers with known hints, call arguments, return vs -> T, and results of calls whose callee declares a return hint produce an IDE/LSP Error by default. Operators and built-in return types are not inferred. Hints are also used by tools (e.g. getSymbols), IDEs, and documentation.
function name(param: Type?, ...) -> ReturnType? {
// param and return type hints are optional and informational only
}
Example:
function greet(name: string) -> string {
return "Hello, " + name;
}
function add(a: int, b: int) -> int {
return a + b;
}
9.2 Function Call
var result = functionName(arg1, arg2);
functionName(); // No return value needed
9.3 Return Statement
Return statements are optional in MALDA functions. A function can:
- Have
return value;- returns the specified value - Have no return statement - last expression wins: if the last statement is an expression, its value is implicitly returned; otherwise returns
null - Have
return;- explicitly returnsnull
This applies to functions, methods, and lambdas (but not constructors). The same rule applies to match case bodies when the match is used as an expression (see 8. Control Structures).
Examples
// Function with explicit return
function add(a, b) {
return a + b;
}
// Last expression wins: no explicit return needed
function process(x) {
var doubled = x * 2;
doubled + 1; // implicitly returned
}
print(process(5)); // Prints 11
// Function without return (last statement is not an expression)
function printMessage(msg) {
print(msg);
// No return - function returns null
}
// Function with explicit null return
function logInfo(message) {
print("Info: " + message);
return; // Explicitly return null
}
// Function that may or may not return a value
function findValue(arr, target) {
var i = 0;
while (i < length(arr)) {
if (arr[i] == target) {
return i; // Return index if found
}
i = i + 1;
}
// No return statement - returns null if not found
}
Using Function Return Values
When calling a function, you can:
- Ignore the return value:
printMessage("Hello"); - Capture the return value:
var sum = add(5, 3); - Use the return value in expressions:
print("Sum: " + add(5, 3));
return. Only when the last statement is not an expression (e.g. print(...)) does the function return null. You can check for null using result == null or use the return value in conditional expressions.
9.4 Recursion
Functions can call themselves recursively:
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
9.5 Standalone Functions vs Methods
- Standalone functions (defined outside classes) are global functions
- Methods are functions defined within classes
- Both use the same syntax, but methods have access to
this
9.6 Lambda Expressions
MALDA supports lambda expressions (anonymous functions) using arrow function syntax. Lambdas are first-class values that can be assigned to variables, passed as arguments, and returned from functions.
Expression Body
Lambdas with a single expression automatically return that expression:
var add = (a, b) => a + b;
var square = x => x * x;
var getValue = () => 42;
print(add(2, 3));
print(square(3));
print(getValue());
Block Body
Lambdas with multiple statements use braces. You can use explicit return, or rely on last expression wins: if the last statement is an expression, its value is implicitly returned.
var process = (x) => {
var result = x * 2;
return result + 1;
};
// Last expression wins: no explicit return needed
var process2 = (x) => {
print("processing " + x);
x * 2; // implicitly returned
};
print(process2(5)); // Prints "processing 5" then 10
Closure Capture
Lambdas capture variables from their enclosing scope, enabling powerful functional programming patterns:
function makeMultiplier(factor) {
return (x) => x * factor; // Captures 'factor' in closure
}
var double = makeMultiplier(2);
print(double(5)); // Prints 10
var triple = makeMultiplier(3);
print(triple(4)); // Prints 12
Usage Examples
// Assign to variable
var comparator = (a, b) => a < b;
// Pass as argument to functions that accept callbacks
function transformArray(arr, transformer) {
var result = [];
for (var i = 0; i < arr.length; i = i + 1) {
result.append(transformer(arr[i]));
}
return result;
}
var numbers = [1, 2, 3, 4];
var doubled = transformArray(numbers, (x) => x * 2);
var squared = transformArray(numbers, (x) => x * x);
print(doubled); // [2, 4, 6, 8]
print(squared); // [1, 4, 9, 16]
// Return from function
function createAdder(n) {
return (x) => x + n;
}
var addFive = createAdder(5);
print(addFive(10)); // Prints 15
this context. If you need this binding, use a regular function or method.
9.7 Decorators
MALDA supports decorators for functions, enabling features like custom tools and REST API endpoints. JavaScript-mode GPU kernels use @shader() — see 26.10.1 Shader kernels.
@within and @budget
Use @within(ms) for a wall-clock deadline on a function body or await prompt(...) / agent.think() turn. Use @budget(tokens: N, tools: N, cost: N?) for resource limits on the same declarations. Do not overload @within’s positional milliseconds argument — budget keys are named. Unknown @budget keys are errors under CLI --strict-types (malda-bounds), same strictness as @within.
@within(5000)
@budget(tokens: 4000, tools: 8)
prompt answer(q) -> Answer {
user: "Question: {q}"
}
tokens— prompt+completion when the backend reports usage; otherwise a best-effortceil(chars / 4)count. Abort, not context trim.tools— number of invocations in that prompt/agent turn, not the length of thetools:/gather:allow-list.cost— optional; enforced only when the backend already exposes usage cost. Omit the key when unused.
MALDA_AGENT_CONTEXT_BUDGET_TOKENS still trims undeclared agent context. It is not a second abort API; declare @budget when you want a hard bound. See Examples/Prompts/prompt_budget.malda. Prompt-specific bounds are covered with the rest of the prompt surface in 10. Prompts.
@pure and @effects
Use @pure() on helpers that must not perform I/O. Use @effects("print", …) to declare an allow-list of side effects on a handler. These are checked under CLI --strict-types / full strict analysis (malda-pure / malda-effects). Prefer validate() on tool or LLM-shaped payloads before impure work — see Examples/Agents/agent_governance_golden.malda and 18. Agent Orchestration. @effects("io") is a name allow-list and does not stop a tool from inventing a path; pass a cap.fileRead token into the handler instead.
@pure()
function normalizeName(name) {
return upper(trim(name));
}
@effects("print")
function handleToolArgs(raw) {
var check = validate("ToolInput", raw);
if (!check.ok) {
print("invalid: " + check.error);
return;
}
print(normalizeName(check.data.name));
}
@Tool Decorator
This is the function decorator. How agents call tools is in 18. Agent Orchestration.
@Tool("tool_name", "Tool description")
function myTool(param1, param2) {
return param1 + param2;
}
REST API Decorators
Routing, middleware, and a complete server are in 27. REST API Server.
@GET("/api/users")
function getUsers() {
return [{"id": 1, "name": "Alice"}];
}
@POST("/api/users")
function createUser(body) {
return {"id": 2, "name": body.name};
}
9.8 Prompts
Named prompt templates use the prompt keyword rather than function. They interpolate parameters, return a PromptInstance, and can be awaited against a schema. See 10. Prompts.
See Also
- 10. Prompts - Prompt templates, await, and schemas
- 11. Classes & Objects - Methods in classes
- 18. Agent Orchestration - Using agents with prompts
- 27. REST API Server - REST decorators