0

I have observed that when we do change a property value of struct, then a new struct object is created.

struct StructureTest {
    var i: Int

    mutating func changeValue(_ val: Int) {
        i = val
    }
}

var st = StructureTest(i: 10) {
    didSet{
        print("struct changed")
    }
}

print("before: \(st)")
st.changeValue(20)
print("after: \(st)")

Output:

before: StructureTest(i: 10)   
struct changed
after: StructureTest(i: 20)

Main thing I have noticed that after changing it's property value. A new struct object is created and assigned to var st.

I do know what are "value types" and what is "copy on assign" feature.

But I am unable to understand that why is it happening here? Maybe I am missing something here? Let me know if you do know the reason for this new struct instance creation.

Along side with this I have observer one more thing that:

If I have a array of structs. Like as:

struct StructureTest {
    var i: Int

    mutating func changeValue(_ val: Int) {
        i = val
    }
}

var arrStructs = [StructureTest(i: 10), StructureTest(i: 20)] {
    didSet {
        print("arrStructs changed")
    }
}

arrStructs[0].changeValue(30)

Output:

arrStructs changed

I am unable to understand that why is array modifying?

As much I can understand from "copy of write" feature on value types. It should happen when an array is modified and array capacity requires to create a new array but in this case array modification reason is not clear to me.

Do let me know If you do know the reason behind that or if you can provide me any reference for clarification.

Sorry for my grammatical mistakes. Hope the essence of problem is clear to you.

Christophe
  • 68,716
  • 7
  • 72
  • 138
Mohd Haider
  • 673
  • 1
  • 5
  • 25
  • 2
    "I do know what are value types" I don't think you do. It is the nature of a value type that it is not mutable in place. Thus, setting a property of a struct means substitution of a new struct. That is why a struct reference, to be mutable, must be `var` and not `let`. See for example my explanation here: https://stackoverflow.com/a/49806545/341994 – matt Apr 09 '19 at 20:51
  • Yes. You are right. That's why I have created a mutable struct instance "st". So I can update it's property. Thanks for your prompt feedback. – Mohd Haider Apr 09 '19 at 20:55

1 Answers1

2

The structs have value semantics, so when you mutate a struct you have assigned a new value to it; ie you changed the value that the variable holds. Array in swift is a generic struct and it therefore also has value semantics (unlike most languages where array is a reference). Therefore if you mutate any element of the array, you have changed the value of the entire array.

Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • Ok. So because of that whenever I will update struct property. It will create a new struct instance and assign it to "st". Just wanted to understand one more thing then. If I do have an array of struct and this array do have 100,000 records. So if I do update any instance property. Then a whole new array of 100,000 records will be created and assigned back to array variable. Is my understanding right? or Is there something am I missing again? – Mohd Haider Apr 09 '19 at 21:01
  • Array has value *semantics* but is not a value type. Therefore its actually implemented as a reference. The new copy of 100,000 records will only occur if you have two things pointing to the array (this is copy on write). If there is only one thing referencing the array then the compiler will just mutate the existing instance. This gives you reference like performance in most cases with value semantics. – Josh Homann Apr 09 '19 at 21:04
  • Ok. Thanks for your answer. I have searched on stack overflow and other various sites and tried to get a proper way to print address of objects in Swift. So can you verify that is it a right way to print address of an array in Swift 5. – Mohd Haider Apr 09 '19 at 21:12
  • func printAddress(_ o: Any ) { print(Unmanaged.passUnretained(o as AnyObject).toOpaque()) } – Mohd Haider Apr 09 '19 at 21:12
  • If it is a right approach to print array instance address in Swift, then I do have some more doubts to clear here. Which I am not able to understand clearly. – Mohd Haider Apr 09 '19 at 21:15
  • That function looks like it prints the address for a refernce type: AnyObject is any reference type. Its not going to print anything for a struct. – Josh Homann Apr 09 '19 at 22:10
  • Ok. I do have a reference to print address of value types. Please take a look at this: https://stackoverflow.com/a/46953018/1707344. If it is the correct way to print address. Then I have observed that after changing arrStructs[0].changeValue(30). I am getting separate memory address for "arrStructs". So that means if I do any changes in value type, then it will create a new copy of it and assigned back to holding variable. If this is right, then it should not a good way to handle arrays in any programming language. So I think I am still misunderstanding something here. – Mohd Haider Apr 10 '19 at 06:01