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.

2
  • 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: stackoverflow.com/a/49806545/341994 Commented Apr 9, 2019 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. Commented Apr 9, 2019 at 20:55

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

8 Comments

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?
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.
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.
func printAddress(_ o: Any ) { print(Unmanaged<AnyObject>.passUnretained(o as AnyObject).toOpaque()) }
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.
|
1

I have read the comments/replies to the post. One more thing/finding, I would like to add here is that when you modify a struct (e.g. changing its property) the entire struct is reinitialized. However the address of that struct (value) remains the same. The new struct is stored at the same location in the stack.

And when we copy a struct, e.g.

var s = SomeStruct()
var copyOfS = s

The address of the "copyOfS" is changed/different (as expected obviously).

1 Comment

"the entire struct is reinitialized" This makes it sound like the init is run again, but it's not. "The new struct is stored at the same location in the stack." To clarify, structs aren't necessarily stored on the stack. They stored directly inline into their "parent". That can be the stack (or even registers!) in the case of a local variable, but for an instance variable of a class, that'll store it directly in the object's memory.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.