Why can't I modify an initialized value-type immediately after its initialization?!
// using swift 5.5
struct Foo {
var x: Int = 0
mutating func add(_ y: Int) -> Foo {
x = y
return self
}
}
var thisFails = Foo().add(42) // ERROR! "Cannot mutate member on immutable value"
var alsoFails = (Foo().add(42)) // Same error
// test 1:
var test1 = Foo()
test1 = test1.add(13) // Modifying 'test1' and assigning 'test1' is OKAY
// test 2:
_ = Foo() // Creating something not assigned to variable is OKAY (but pointless)
// test 3:
extension Foo: CustomStringConvertible {
var description: String { "Weird \(x)" }
}
print("Test3: \(Foo())") // Creating something not assigned to variable is OKAY
Why is the statement Foo().add(42)
problematic?
- Save some space on the stack (for a
Foo
) and initialize it (like is in test#3); - Use it for function
add(_)
; - Take the returned value from
add(_)
and assign to variable;
Unless I've missed something from Swift's Initialization documentation, I don't understand why this fails.
CodePudding user response:
It's because Foo is a struct and a struct is a value type. This means that you cannot really mutate a Foo in place; you have to replace one Foo with another. When you call add
on a Foo, you actually get a different Foo (with a different x
) and you replace the old one with the new one. This allows you to do that:
var test1 = Foo()
test1 = test1.add(13) // okay too
test1.add(14) // okay too
That's fine, because all along we have a shoebox, test1
, and we can assign into it (var
), which is what is required in order to mutate a struct. test1
holds a Foo, and when we "mutate" it by saying add
, we throw away that Foo and put a different Foo in its place.
Its place.
But Foo().add(13)
gives us nothing to assign into so you can't say it. It's incoherent. There is no "place" to put the new Foo.