49

I have a struct :

public struct MyStruct {
  public var myInt: Int = 0
  ...
}

I have a extension of MyStruct:

extension MyStruct {

  public func updateValue(newValue: Int) {
     // ERROR: Cannot assigned to property: 'self' is immutable
     self.MyInt = newValue
  }
}

I got the error showing above, I know I can fix the error by several ways, e.g. add a mutating keyword before func.

I am here not asking how to fix the error, but ask why swift doesn't allow this kind of value assignment ? I need an explanation besides a fix.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Leem
  • 17,220
  • 36
  • 109
  • 159
  • 1
    Compare https://stackoverflow.com/questions/24035648/swift-and-mutating-struct. – Martin R Mar 13 '18 at 10:11
  • 1
    Or directly from the Swift documentation https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html: *"Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods. However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method."* – Martin R Mar 13 '18 at 10:11

3 Answers3

77

struct is a value type. For value types, only methods explicitly marked as mutating can modify the properties of self, so this is not possible within a computed property.

If you change struct to be a class then your code compiles without problems.

Structs are value types which means they are copied when they are passed around.So if you change a copy you are changing only that copy, not the original and not any other copies which might be around.If your struct is immutable then all automatic copies resulting from being passed by value will be the same.If you want to change it you have to consciously do it by creating a new instance of the struct with the modified data. (not a copy)

Dixit Akabari
  • 2,419
  • 13
  • 26
  • 1
    Although structs are pass by value there's copy on write which means that for structs that are not mutated they are essentially copying around the same memory just like a reference type. Otherwise this would cause a huge performance problem. All the OP has to do is mark his function `mutating`. – SmileBot Sep 19 '22 at 19:28
18

A tricky one: mark it as @State. Structs are immutable objects so normal properties cannot be modified after their initializer. Adding this kind of label you are converting it into mutating properties.

Community
  • 1
  • 1
oskarko
  • 3,382
  • 1
  • 26
  • 26
  • 1
    Could you elaborate more on this? – Andy Theos Jul 15 '22 at 12:10
  • 3
    Sure! Structs are immutable objects so normal properties cannot be modified after their initializer. Adding this kind of label you are converting it into mutating properties. – oskarko Jul 15 '22 at 15:50
0

Because a Struct is a value type, and therefore should be immutable

stevenpcurtis
  • 1,907
  • 3
  • 21
  • 47
  • 2
    Why value type should be immutable? – Leem Mar 13 '18 at 10:11
  • 3
    Value types are mutable, you just have to declare them as mutable. – Cristik Mar 13 '18 at 10:36
  • So by default they are immutable, right? Default, value type immutable. Value type immutable. – stevenpcurtis Mar 13 '18 at 12:28
  • 1
    structs are not immutable. we have `vars` and `mutating` funcs. Not a problem. The OP needs to mark his function `mutating`. When you mutate a struct though notice it makes a copy of itself. So if you attach a property observer it will call `didSet`. classes will not make copies of themselves when mutated. So, if you have a property to one and mutate the instance the `didSet` observer is not called. – SmileBot Sep 19 '22 at 19:29