Example: manage two sets of accounts
Combine types, functions, memory and Agent calls in a small project. Maintain two independent sets of account balances, then process numbers with two different increment functions.
You will learn to split packages, reference identically named types, call another Agent from a skill and read fields from returned values.
Prepare the project
Download the account example (ZIP) and extract it into /tmp to get /tmp/aal-composition. First complete the compiler setup in AAL introduction.
aal-composition/
left/
aal.toml
src/main.aal
right/
aal.toml
src/main.aal
app/
aal.toml
aal.lock
src/main.aal
left and right are account packages; app calls both. Each has its own manifest. The application declares dependencies using relative paths. The lock file is included with the source.
Define account types and memory
Open left/src/main.aal:
struct Account
balance: Int
agent Worker is Agent
memory scope "account" strict
balance: Int = 10
public
ability add(amount: Int) -> Account effects(memory.read, memory.write)
balance = memory.require("balance") + amount
memory.store("balance", balance)
return Account(balance: balance)
Account is the returned result; its balance field holds the balance. The balance in memory is Worker state, initially 10.
Each add reads the old balance, adds amount, stores the new value, and returns an Account. Reading and writing require memory.read and memory.write respectively.
The right package uses the same type and Agent names but starts at 100. Package aliases distinguish these objects.
Compose calls in the application
Open app/src/main.aal:
agent Main is Agent
private
fn left_balance(account: left.Account) -> Int effects()
return account.balance
skill delegation
fn increment() -> right.Account effects(agent)
return agent("right.Worker").add(1)
public
ability run() -> List<Int> effects(agent)
factory = (offset: Int) => (value: Int) => value + offset
add_two = factory(2)
add_ten = factory(10)
a = agent("left.Worker").add(1)
b = self.delegation.increment()
again = agent("left.Worker").add(2).balance
return [self.left_balance(a), again, b.balance, add_two(3), add_ten(3), factory(20)(1)]
Read run in this order:
- factory accepts offset and returns a function that retains it. add_two and add_ten retain 2 and 10.
agent("left.Worker").add(1)increments the left balance by 1 and assigns the returned Account to a.self.delegation.increment()enters the private skill, which calls the right Worker. Skills organize steps; external callers still use public abilities.agent("left.Worker").add(2).balanceadds another 2 on the left and immediately reads the returned balance field.- The final line collects balances and closure results.
Check and run
Run from the AAL repository:
cargo run --locked --bin aalc -- lock /tmp/aal-composition/app
cargo run --locked --bin aalc -- check /tmp/aal-composition/app
cargo run --locked --bin aalc -- run /tmp/aal-composition/app --agent Main --ability run --args '{}' --state-dir /tmp/aal-composition/state --invocation composition-1
On first use of this state directory, the result is:
[11, 13, 101, 5, 13, 21]
| Result | Source |
|---|---|
| 11 | Left starts at 10, then adds 1 |
| 13 | Left adds another 2 |
| 101 | Right starts at 100, then adds 1 |
| 5 | add_two(3): 3 + 2 |
| 13 | add_ten(3): 3 + 10 |
| 21 | factory(20)(1): 1 + 20 |
The right operation does not change the left balance. The closures also retain different offsets.
Try a change
Change add_two's offset to 5. Update the lock and run with a new invocation ID; observe the fourth result. Keeping the state directory retains prior balances. Use a new directory to start from initial values.
Then replace self.left_balance(a) with self.left_balance(b). Update the lock and run check. You will get type error E210: the function requires left.Account, but b is right.Account. Identical fields do not make these types interchangeable. Restore a and update the lock to continue.
Continue learning
The two Workers are defined separately in the project, not created by a runtime instance factory. Read closure factories for functions returning functions, or projects and distribution to share a project.