Eric D Eric D - 6 months ago 47
Swift Question

Can I use `inout` with protocol extensions?

I have a protocol and its extension, and a class conforming to the protocol.

protocol WarAbilities {
var strength: Int { get set }
func attack(inout opponent: WarAbilities)
}

extension WarAbilities {
func attack(inout opponent: WarAbilities) {
opponent.strength -= 1
}
}

class Warrior: WarAbilities {
var strength: Int

init(strength: Int) {
self.strength = strength
}
}


Now if I want to make two warriors fight:

let thug1 = Warrior(strength: 10)
let thug2 = Warrior(strength: 30)

thug1.attack(&thug2)


I get this error message:


error: cannot pass immutable value of type 'WarAbilities' as inout argument


Adding
mutating
looked promising:

protocol WarAbilities {
var strength: Int { get set }
mutating func attack(inout opponent: WarAbilities)
}

extension WarAbilities {
mutating func attack(inout opponent: WarAbilities) {
opponent.strength -= 1
}
}


But the compiler isn't happy either and I fail to understand what the new error message means:


error: cannot pass immutable value as inout argument: implicit conversion from 'Warrior' to 'WarAbilities' requires a temporary


Since
Warrior
conforms to
WarAbilities
I thought one of those would work - but it looks like Swift doesn't have this kind of... covariance? I'm not even sure what I'm talking about here.

What's my mistake?

Answer

Make it a class protocol and get rid of the (then) unnecessary inout stuff:

protocol WarAbilities : class {
    var strength: Int { get set }
    func attack(opponent: WarAbilities)
}

extension WarAbilities {
    func attack(opponent: WarAbilities) {
        opponent.strength -= 1
    }
}

class Warrior: WarAbilities {
    var strength: Int

    init(strength: Int) {
        self.strength = strength
    }
}

let thug1 = Warrior(strength: 10)
let thug2 = Warrior(strength: 30)

thug1.attack(thug2)

thug2.strength // 29

(Indeed it's rather unclear to me why you need a protocol here at all; since Warrior is a class, you can just make WarAbilities its superclass.)