Edit for new readers: there will be tx-level caching in next releases, first call to a contract parses the module and subsequent calls get the already parsed module, resulting in batched calls not being needed. Thus this is not a standard you'd want to enforce unless you're looking for something very specific.
The current metering makes it very expensive to make a new VM instantiation (i.e a cross contract call), which makes an invocation very expensive when it needs to call a contract multiple times. For example, as @wide jolt pointed out (#1113855389100945439 message) they'll need to add batched price retrievals in order not to make clients instantiate many VMs and incurr in higher gas prices or even getting their transaction reverted because of usage costs.
I think that the standard token interface should enforce a similar design for batch-retrieving balances:
fn batched_balance(e: Env, ids: Vec<Address>) -> Vec<i128> {
let mut balances: Vec<i128> = Vec::new(&e);
for id in ids.iter() {
balances.push_back(read_balance(&e, id.unwrap()))
}
balances
}
This makes invocations that require getting more than one balance much more efficient. The delta cpuIns cost between these two functions is 994383:
#[contractimpl]
impl ContractB {
pub fn bal_unopt(env: Env, contract: Address, x: Address, y: Address) {
let client = contract_a::Client::new(&env, &contract);
client.balance(&x);
client.balance(&y);
}
pub fn bal_opt(env: Env, contract: Address, x: Address, y: Address) -> Vec<i128> {
let client = contract_a::Client::new(&env, &contract);
client.batched_balance(&vec![
&env,
x,
y,
])
}
}