Reputation: 53
I'm trying to understand the difference between value and reference type. And now I want to use function from the apple guide:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
and if I want to use this is function I will write this code
swapTwoInts{&firstIntStruct, &secondIntStruct}
I understand that we must put in this function reference type, but Int is a value type, therefore we use &.
In another hand, when I try change Int to my class in the swap function, I also must write & before instance of my class.
Why I must do it, if it is the reference already?
Upvotes: 4
Views: 2454
Reputation: 5679
I would like to explain it with example. As @Alexander mentioned, for th function with Int
as parameter:
1. Pass by value
It will mutate the copies, and not the original references of caller.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
You can see that
func swapTwoInts(_ a: Int, _ b: Int) { }
If has changed the values of p and q, where self.x and self.y are unchanged. As this function is passing the values of x and y not their reference.
2. Pass by reference:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { }
It passes the reference of self.x and self.y and that's why you don't have to mutate them again as you did by taking p and q in previous type. Because it will take mutating object with var x
and var y
.
You can see that, a and b have values of references in logs and changing a and b has changed the self.x and self.y as well because a and b has the same reference( address) of x and y.
Upvotes: 3
Reputation: 2014
So there a few lower level memory components that are at play to make full sense of this.
1) When you create a value or reference type you have a new variable on the stack. That variable is either the actual data in the case of a value type or a pointer to the data in the case of a reference type.
2) When you call a function, it creates a new part of the stack and it creates new variables on the stack (which are let
instances in swift) that copy the variable passed in. So for value types it does a deep copy and for reference types it copies the pointer.
So what this means is that when you use inout
you are saying, take the memory address of this variable and update the data it contains. So you can either give a value type new data or a reference type a new pointer address and it will change outside of the scope of the swap function. It makes it a var
(the same one as what is passed in) instead of let
like normal.
Upvotes: 1
Reputation: 63271
Suppose we wrote the hypothetical function you're talking about:
class C {}
func swapTwoC(_ lhs: C, rhs: C) {
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
The immediate problem is that lhs
and rhs
are immutable. To mutate them, we would need to make mutable copies:
func swapTwoC(_ lhs: C, rhs: C) {
var lhs = lhs; var rhs = rhs
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
But now the problem is that we're mutating our copies, and not the original references our caller gave us.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
When you have an inout C
, and you pass in &myObject
, what you're actually passing in is a reference to your reference to myObject
. When the function arguments are copied, what's copied is this "ref to a ref". The function can then use that "ref to a ref" to assign a new value to the reference myObject
the caller has
Upvotes: 8