Predict the output
Two withdrawals of 80 run at the same time on a balance of 100. What can the final balance be?
actor Account {
var balance = 100
func withdraw(_ amount: Int) async -> Bool {
guard balance >= amount else { return false }
await audit.log(amount) // suspends
balance -= amount
return true
}
}
async let a = account.withdraw(80)
async let b = account.withdraw(80)
_ = await (a, b)Hint 1 of 2
What can happen while the first call is suspended?
Hint 2 of 2
When does the subtraction happen relative to the await?
Choose an answer, then open Show answer below to check it.
Show answer
Answer: B It can be -60
Correct. Both calls pass the guard before either one subtracts, so both withdraw.
Why not the others?
- A Always 20, because the actor runs one call at a time. One call at a time is true only between suspension points. The second call runs while the first waits at
await. - C Always 100, because both calls fail. The first call always passes the guard; the balance starts at 100.
- D It doesn't compile without a lock. It compiles. Actors need no locks; the bug is logical, not a compile error.
Text version
| Version | What runs when | Finishes at |
|---|---|---|
| Call A |
| t = 1.4 s |
| Call B |
| t = 1.7 s |