struct MyStruct { var count = 0 mutating func add(amount: Int) { count += amount } } var myStruct = MyStruct() [1, 2, 3, 4].forEach(myStruct.add) // Partial application of 'mutating' method is not allowed
Why isn't using forEach
like this allowed for mutating methods? I'm aware that I could do
for number in [1, 2, 3, 4] { myStruct.add(number) }
or
[1, 2, 3, 4].forEach { myStruct.add($0) }
instead, but neither are as clean as
[1, 2, 3, 4].forEach(myStruct.add)
The key to a value type is that assignment creates a copy. This contract also affects how people can reason about their code. For example if you're passed an Int
into a method, you can be confident that the value won't change out from under you, even if the original int passed in gets sent off to another thread and has calculations done elsewhere.
Same is true for structs. This is why in swift when defining methods that may alter 'self', if it's a value type you have to define it as 'mutating'. What this says is that it will simultaneously reassign to your variable with the new value. So for example When you call your add method with '3', you can think of it performing something similar to:
var myStruct = MyStruct() var tmp = myStruct tmp.count = tmp.count + 3 myStruct = tmp
Now the reason that you are hitting an error is because partially applying a mutating function would break that contract. If you are able to save a closure like let myStructAdd = myStruct.add
, then at some later point you could call myStructAdd(3)
and it would try to change myStruct. This would give reference semantics to a value type since now you have the power to alter myStruct at a later point, even from a different method.
In short, swift is giving you a convenience by providing 'mutating' methods for code readability, with the caveat that it has to happen all at once so as not to break the value type contract.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With