Mutating protocol extension function forces class to be declared with var

Hi,
I'm a bit confused by the behavior of the following code. Why is it ok to call mutatingProtocolFunction() on an object declared with let, but not mutatingExtensionFunction()?

protocol hasMutatingFunction {
    mutating func mutatingProtocolFunction()
}

extension hasMutatingFunction {
    mutating func mutatingExtensionFunction() {
        mutatingProtocolFunction()
        mutatingProtocolFunction()
    }
}

class C : hasMutatingFunction {
    var count: Int = 0

    func increment() {
        count += 1
    }

    func mutatingProtocolFunction() {
        count += 5
    }
}

let c = C()
c.increment() // works
c.mutatingProtocolFunction() // works
c.mutatingExtensionFunction() //  error: cannot use mutating member on immutable value: 'countdown' is a 'let' constant

And there's an interesting related discussion here.

That is:

protocol HasMutatingFunction {
    mutating func mutatingProtocolFunction()
    init()
}

extension HasMutatingFunction {
    mutating func mutatingExtensionFunction() {
        mutatingProtocolFunction()
        mutatingProtocolFunction()
        self = Self.init() // <--- Note that this is OK here.
    }
}

class C : HasMutatingFunction {
    var count: Int = 0
    required init() { }
    func increment() { count += 1 }
    func mutatingProtocolFunction() {
        count += 5
        // self = Self.init() // <--- But not here.
    }
}
1 Like

Thanks for the links and explanation. How does stdlib's Sequence and IteratorProtocol solve this? next() is a mutating function, there are a lot of extensions (e.g. drop(while:)) and i can implement a custom Sequence with structs and classes...

I found this workaround. It's a bit awkward, but at least it works with structs and classes.

protocol hasMutatingFunction {
    mutating func mutatingProtocolFunction()
}

extension hasMutatingFunction {
    mutating func mutatingExtensionFunction() {
        _mutatingExtensionFunction(this: &self)
    }
}

extension hasMutatingFunction where Self: AnyObject {
    func mutatingExtensionFunction() {
        var this = self
        _mutatingExtensionFunction(this: &this)
    }
}

private func _mutatingExtensionFunction<T: hasMutatingFunction>(this: inout T) {
        this.mutatingProtocolFunction()
        this.mutatingProtocolFunction()
}