Browse the documentation

AEL 1.0.0

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

KindDeclaredCallable from
Helper functionfn in any component's fileThat component and its extension files only
Global functionglobal <name>(…) in <name>.global.aelEvery file in the same folder and every folder below it, with no import
Reusable functionreuse <name>(…) in <name>.reuse.aelA file in the same folder or a folder below it that imports the file in its header
Function in another languagefn <lang> <name>(…) beside a component's helpers, or <lang> <name>(…) in <name>.<lang>.aelThe 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));
}
  • quote calls round_cents without an import, because round_cents.global.ael is in an ancestor folder.
  • quote calls discount because its header imports discount.reuse.ael.
  • quote cannot call share: it is a helper, private to discount.
  • shipping/rates.node.ael can call round_cents, but never discount, not even with an import, because pricing/ is a sibling folder.
  • A file directly in shop/ cannot call discount either: 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, and pub subagent is refused; see Subagents.
  • No import reaches a function in another language, or the helpers of any file.

When names collide

  1. Names in the function itself, and the component's own helpers, come first.
  2. 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.
  3. Two eligible functions of one name in the same folder are refused as ambiguous.
  4. 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 as refer server/http select get;. See Using packages.