inout
does not disappear on a class method, because the actual value being passed is the reference to the object, and class methods are never allowed to rebind self
. This is somewhat of an artificial constraint—we could in theory allow mutating
methods on classes, and those could change the self
binding—but that would more likely than not be confusing, since class methods generally want to mutate the current object without affecting the value of the self
parameter itself. borrow
and take
on the other hand do make sense for self
on class methods, and they would affect the reference-counting convention used to pass the self
reference.
This can be demonstrated with the use of default implementations.
protocol P {
init(value: Int)
var value: Int { get }
mutating func increment()
}
extension P {
mutating func increment() {
self = Self(value: value + 1)
}
}
final class C: P {
let value: Int
init(value: Int) {
self.value = value
}
}
do {
var x = C(value: 0)
x.increment()
x.increment()
print("C(value: \(x.value))") // prints: C(value: 2)
}
C.increment is a mutating function, even though C is a class.
Wouldn't it be confusing to have two different ways of expressing the same thing? Shouldn't we have only one way of expressing that a function can mutate a value type?
I'm not against func mutate(self: inout Self)
to get rid of the extra keyword mutating
and streamline things to just inout
. But that doesn't seem to be your goal here, so I'm confused about how this is going to make things easier.
Sounds like things are more complicated with multiple options to express the same thing – without any of the two options being clearly shorter (like with [Int]
vs Array<Int>
) so I don't see any of the two alternatives as "syntactic sugar". Am I missing something?