Wike
Wike

Reputation: 53

Inout in swift and reference type

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

Answers (3)

Ankit Jayaswal
Ankit Jayaswal

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.

enter image description here

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.

enter image description here

Upvotes: 3

bscothern
bscothern

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

Alexander
Alexander

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

Related Questions