While reading @Douglas_Gregor's Swift for C++ Practitioners, I came across an example where self was being assigned to in a struct, which prompted me to ask myself the following question.
What is actually stored in a variable that contains a struct value?
Here is a simple example that demonstrates this:
struct Foo {
private var u: Int;
init (u: Int) {
self.u = u
}
}
extension Foo {
var bar: Int {
get {
self.u
}
set {
self = .init (u: newValue)
}
}
}
var p = Foo (u: 2)
print (p)
// Foo (u: 2)
p.bar = 3
print (p)
// Foo (u: 3)
The above program creates an instance of Foo, and then changes the value of that instance's only property bar.
var p = Foo (u: 2)
Q: What is stored in the variable p?
p.bar = 3
The setter changes the value of self, by assigning a new instance to it.
Q: How does this new value of self end up in the variable p?
Interestingly enough, Swift does not allow assignment to self in a class instance.
class Foo {
private var u: Int;
init (u: Int) {
self.u = u
}
}
extension Foo {
var bar: Int {
get {
self.u
}
set {
self = .init (u: newValue) // Cannot assign to value: 'self' is immutable
}
}
}
Setters on structs are mutating by default. Mutating methods pass self inout.
This program is effectively the exact same as the one you wrote:
struct Foo {
private var u: Int
init(u: Int) {
self.u = u
}
static func set(_ `self`: inout Self, _ newValue: Int) {
self = .init(u: newValue)
}
}
do {
var foo = Foo(u: 2)
print(foo)
Foo.set(&foo, 3)
print(foo)
}
Class methods aren't allowed to be mutating because it's usually not what you want for a reference type, and it's potentially confusing. It's entirely artificial, and if you implement a protocol with a default implementation of a mutating method, it will be able to reassign self.
BTW, isn't this a miss-feature? I understand it could be potentially useful for something (now that we have it), but it does look a hack and I wonder does it pass the "if we didn't have this feature already would we introduce it now" test.