Here’s some toy code demonstrating an issue I’ve run into. It’s a simple bank account model:
protocol Account {
var balance: Double { get }
mutating func deposit(amount: Double)
mutating func withdraw(amount: Double)
init(initialAmount: Double)
mutating func transfer(to account: inout Account, amount: Double)
}
extension Account {
mutating func transfer(to account: inout Account, amount: Double) {
withdraw(amount: amount)
account.deposit(amount: amount)
}
}
struct EconomyAccount: Account {
var balance: Double
init(initialAmount: Double) {
balance = initialAmount
}
mutating func deposit(amount: Double) {
balance += amount
}
mutating func withdraw(amount: Double) {
balance -= amount
}
}
var account = EconomyAccount(initialAmount: 20)
account.deposit(amount: 100)
account.balance
var account2 = EconomyAccount(initialAmount: 30)
account.transfer(to: &account2, amount: 300) // Error: EconomyAccount is not Account
account2 is a subtype of the Account type however the transfer() function doesn’t allow me to pass it in. Implying that the parameter type is invariant.
However I can somewhat workaround this by making a copy of the variable:
var account2 = EconomyAccount(initialAmount: 30)
var cpy:Account = account2 // Copy to type Account
account.transfer(to: &cpy, amount: 300)
This workaround seems like something that would be done implicitly via passing a subtype into a parameter.
In addition this works for inout params where the type is generic. Which as a result is covariant:
mutating func transfer<T: Account>(to account: inout T, amount: Double)
This leads me to ask if there is a specific reason that swift doesn’t have covariance for inout parameters as is, or is this a feature being worked on.
Any input would be appreciated, Thanks