Functions and visibility
Sharing in AEL, the Agent Engineering Language, follows three clear rules: helpers stay private to their component, shared functions are visible by folder, and reusable functions are imported explicitly. The check enforces each rule before anything runs.
Declaring a function
fn with_tax(amount: u64, percent: u64) -> u64 {
return amount + amount * percent / 100;
}
- Every parameter and the result have explicit types. A function that returns nothing declares
-> (). - Parameters are not reassignable unless declared
mut:fn next(mut n: u64) -> u64. - A function can call functions declared further down the same file.
- Every call names its function directly. Functions are not values: there are no closures, and you cannot store a function or pass it as an argument.
- Two functions with the same name in one file are refused; AEL has no overloading.
The primary of a component uses its role word instead of fn, as in reuse twice(value: i64) -> i64. main can leave out its result when it returns nothing.
Recursive calls are checked against the target's stack limits: on the smallest boards, a recursion whose depth cannot be bounded fails to build.
Three kinds of function
| Kind | Declared | Callable from |
|---|---|---|
| Helper function | fn in any component's file | That component and its extension files only |
| Global function | global <name>(…) in <name>.global.ael | Every file in the same folder and every folder below it, with no import |
| Reusable function | reuse <name>(…) in <name>.reuse.ael | A file in the same folder or a folder below it that imports the file in its header |
| Function in another language | fn <lang> <name>(…) beside a component's helpers, or <lang> <name>(…) in <name>.<lang>.ael | The file that declares it and that file's extension files only |
"Global" describes where a function is visible, never shared state: AEL has no global variables.
Your application can hold private functions written in other languages, with typed AEL signatures. Such a function is always private: pub fn python is refused, no import reaches it, and the primary of a language file is private to that file and its extension files. To share one, wrap it in a global or reusable function written in AEL; Functions in other languages shows how.
An example
shop/
round_cents.global.ael # global round_cents(…)
pricing/
discount.reuse.ael # reuse discount(…)
quote.node.ael
shipping/
rates.node.ael
# pricing/discount.reuse.ael
reuse discount(amount: u64, percent: u64) -> u64 {
return amount - share(amount, percent);
}
fn share(amount: u64, percent: u64) -> u64 {
return amount * percent / 100;
}
# pricing/quote.node.ael
import "./discount.reuse.ael";
node quote(amount: u64) -> u64 {
return round_cents(discount(amount, 10));
}
quotecallsround_centswithout an import, becauseround_cents.global.aelis in an ancestor folder.quotecallsdiscountbecause its header importsdiscount.reuse.ael.quotecannot callshare: it is a helper, private todiscount.shipping/rates.node.aelcan callround_cents, but neverdiscount, not even with an import, becausepricing/is a sibling folder.- A file directly in
shop/cannot calldiscounteither: a folder never reaches into the folders below it.
Imports
- An import sits in the file's header, before the first declaration:
import "../welcome.reuse.ael";. - The path is relative to the importing file and names the whole file name. It must lead to the file's own folder or a folder above it, inside the project.
- An import makes one reusable function available, and nothing else: not the file's helpers, and not what that file imports in turn.
- A reusable function that is not imported is invisible, even in the same folder.
- A subagent is imported the same way, by its file, as in
import "./issue_reader.subagent.ael";, from the importing file's folder or a folder above it. Nothing imports a subagent automatically, through another file's import or with a wildcard, andpub subagentis refused; see Subagents. - No import reaches a function in another language, or the helpers of any file.
When names collide
- Names in the function itself, and the component's own helpers, come first.
- Then AEL looks in the caller's folder, then in each folder above it up to the project root. The nearest folder that has an eligible global or imported reusable function of that name wins.
- Two eligible functions of one name in the same folder are refused as ambiguous.
- If the nearest function has the wrong types, the call fails. AEL never falls back to a function further away that happens to fit.
A shared function's body always uses the names visible where it is written. Calling it from another folder never changes which functions its body calls.
Components and packages
These rules are for shared functions. Components are connected differently:
- An agent names its nodes and edges in its configuration, such as
nodes: [summarizer = summarize]. Those references are typed and may cross folders, but they never expose a component's helpers. See Agents, nodes and edges. - A package's exports are named in the header with
refer, such asrefer server/http select get;. See Using packages.