Skip to content
Kavachकवच

Your Own Capabilities: When a call is refused

● Intermediate3 min

A refused call fails with Denied(reason), an ordinary error: match on it like any other.

type PayError = Declined | Unavailable | Denied(reason: String)

capability Payments {
    fn refund(order: Int, amount: Int) ! PayError
}

type Bank: Payments {
    fn refund(self, order: Int, amount: Int) ! PayError {
        print("refunded {amount} on order {order}")
    }
}

agent Refunder {
    can Payments.refund

    limit Payments.refund {
        amount <= 500
    }

    on refund(order: Int, amount: Int) ! PayError {
        try Payments.refund(order, amount)
    }
}

fn main() {
    const bot = Refunder.start(Payments: Bank())
    for r in [(order: 1, amount: 200), (order: 2, amount: 900)] {
        bot.refund(r.order, r.amount) catch e => match e {
            PayError.Denied(reason) => print("order {r.order}: blocked, {reason}"),
            PayError.Declined => print("order {r.order}: the bank said no"),
            PayError.Unavailable => print("order {r.order}: try again later"),
            _ => print("order {r.order}: {e}"),
        }
    }
}

The program ran and printed:

kavach run own-refused.kav

refunded 200 on order 1order 2: blocked, limit broken: amount <= 500
own-refused.kav: Kavach code, then what running it prints

The reason says what refused it: a broken limit, a person who said no, or no implementation. Handle Denied apart from the system's own errors, such as a declined card or a bank that is down.

The _ arm is needed: a send can always fail with something else too, such as a panic in the handler.