# Example: manage two sets of accounts | EasyNet Docs Source: https://easynet.run/docs/aal/reference/composition # 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)](https://easynet.run/examples/aal-composition.zip) and extract it into /tmp to get /tmp/aal-composition. First complete the compiler setup in [AAL introduction](https://easynet.run/docs). ``` 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 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).balance adds 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] ``` ResultSource11Left starts at 10, then adds 113Left adds another 2101Right starts at 100, then adds 15add_two(3): 3 + 213add_ten(3): 3 + 1021factory(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](https://easynet.run/docs/aal/reference/closures) for functions returning functions, or [projects and distribution](https://easynet.run/docs/aal/reference/projects) to share a project.