Last active
March 31, 2021 00:38
-
-
Save RoyalIcing/b2af1072b3475a5eb2dd7d3051a70830 to your computer and use it in GitHub Desktop.
Defining Actors in Swift with Protocols
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol Actor : AnyObject, Sendable { | |
associatedtype State | |
isolated var state: State | |
} | |
struct BankAccountState { | |
var balance: Double | |
mutating func deposit(amount: Double) { | |
assert(amount >= 0) | |
balance = balance + amount | |
} | |
mutating func withdraw(amount: Double) throws { | |
assert(amount >= 0) | |
if amount > state.balance { | |
throw BankError.insufficientFunds | |
} | |
balance = balance - amount | |
} | |
} | |
class BankAccount : Actor { | |
let accountNumber: Int | |
var state: BankAccountState | |
init(accountNumber: Int, initialDeposit: Double) { | |
self.accountNumber = accountNumber | |
self.state = BankAccountState(balance: initialDeposit) | |
} | |
async var balance: Double { await state.balance } | |
mutating func transfer(amount: Double, to other: BankAccount) async throws { | |
// Safe: this operation is the only one that has access to the actor's isolated | |
// state right now, and there have not been any suspension points between | |
// the place where we checked for sufficient funds and here. | |
try state.withdraw(amount: amount) | |
print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)") | |
// Safe: the deposit operation is placed in the `other` actor's mailbox; when | |
// that actor retrieves the operation from its mailbox to execute it, the | |
// other account's balance will get updated. | |
await other.deposit(amount: amount) | |
} | |
mutating func deposit(amount: Double) { | |
state.deposit(amount: amount) | |
} | |
} | |
var bankAccountA = BankAccount(accountNumber: 7, initialDeposit: 200) | |
var bankAccountB = BankAccount(accountNumber: 42, initialDeposit: 200) | |
await bankAccountA.deposit(amount: 200) | |
await bankAccountA.transfer(amount: 100, to: bankAccountB) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment