86

When passing a class or primitive type into a function, any change made in the function to the parameter will be reflected outside of the class. This is basically the same thing an inout parameter is supposed to do.

What is a good use case for an inout parameter?

Qbyte
  • 12,753
  • 4
  • 41
  • 57
4thSpace
  • 43,672
  • 97
  • 296
  • 475

8 Answers8

135

inout means that modifying the local variable will also modify the passed-in parameters. Without it, the passed-in parameters will remain the same value. Trying to think of reference type when you are using inout and value type without using it.

For example:

import UIKit

var num1: Int = 1
var char1: Character = "a"

func changeNumber(var num: Int) {
    num = 2
    print(num) // 2
    print(num1) // 1
}
changeNumber(num1)

func changeChar(inout char: Character) {
    char = "b"
    print(char) // b
    print(char1) // b
}
changeChar(&char1)

A good use case will be swap function that it will modify the passed-in parameters.

Swift 3+ Note: Starting in Swift 3, the inout keyword must come after the colon and before the type. For example, Swift 3+ now requires func changeChar(char: inout Character).

Community
  • 1
  • 1
Lucas Huang
  • 3,998
  • 3
  • 20
  • 29
  • 2
    Is that well-defined behaviour? Because the spec seems to say that `inout` gets copied back when the function returns. So should `char1` already be `a` within the function? – Thilo Dec 28 '15 at 01:25
  • Re: well-defined behaviour: @drfi's answer addresses this: "Do not depend on the behavioral differences between copy-in copy-out and call by reference" – Thilo Dec 28 '15 at 01:27
  • @Thilo You are correct, this example contains code that may not behave well-defined, and at the very least are not in line with the `inout` language ref. I'll add an example into my answer. – dfrib Dec 28 '15 at 01:45
  • 2
    Note that `var` in your `changeNumber` function will be deprecated in future versions of Swift. – timbo Dec 28 '15 at 02:20
  • It's just an example to show the differences. It's not for actual practice. – Lucas Huang Dec 28 '15 at 05:41
  • calling `changeNumber(num1)` causes the error. "Simultaneous accesses to 0x7fe71270a578, but modification requires exclusive access." checking on Xcode 11.4.1 – Adnan Ali Dec 04 '20 at 22:37
48

From Apple Language Reference: Declarations - In-Out Parameters:

As an optimization, when the argument is a value stored at a physical address in memory, the same memory location is used both inside and outside the function body. The optimized behavior is known as call by reference; it satisfies all of the requirements of the copy-in copy-out model while removing the overhead of copying. Do not depend on the behavioral differences between copy-in copy-out and call by reference.

If you have a function that takes a somewhat memory-wise large value type as argument (say, a large structure type) and that returns the same type, and finally where the function return is always used just to replace the caller argument, then inout is to prefer as associated function parameter.

Consider the example below, where comments describe why we would want to use inout over a regular type-in-return-type function here:

struct MyStruct {
    private var myInt: Int = 1

    // ... lots and lots of stored properties

    mutating func increaseMyInt() {
        myInt += 1
    }
}

/* call to function _copies_ argument to function property 'myHugeStruct' (copy 1)
   function property is mutated
   function returns a copy of mutated property to caller (copy 2) */
func myFunc(var myHugeStruct: MyStruct) -> MyStruct {
    myHugeStruct.increaseMyInt()
    return myHugeStruct
}

/* call-by-reference, no value copy overhead due to inout opimization */
func myFuncWithLessCopyOverhead(inout myHugeStruct: MyStruct) {
    myHugeStruct.increaseMyInt()
}

var a = MyStruct()
a = myFunc(a) // copy, copy: overhead
myFuncWithLessCopyOverhead(&a) // call by reference: no memory reallocation

Also, in the example above---disregarding memory issues---inout can be preferred simply as a good code practice of telling whomever read our code that we are mutating the function caller argument (implicitly shown by the ampersand & preceding the argument in the function call). The following summarises this quite neatly:

If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

From Apple Language Guide: Functions - In-Out Parameters.


For details regarding inout and how it's actually handled in memory (name copy-in-copy-out is somewhat misleading...)---in additional to the links to the language guide above---see the following SO thread:


(Edit addition: An additional note)

The example given in the accepted answer by Lucas Huang above tries to---in the scope of the function using an inout argument---access the variables that were passed as the inout arguments. This is not recommended, and is explicitly warned not to do in the language ref:

Do not access the value that was passed as an in-out argument, even if the original argument is available in the current scope. When the function returns, your changes to the original are overwritten with the value of the copy. Do not depend on the implementation of the call-by-reference optimization to try to keep the changes from being overwritten.

Now, the access in this case is "only" non-mutable, e.g. print(...), but all access like this should, by convention, be avoided.

At request from a commenter, I'll add an example to shine light upon why we shouldn't really do anything with "the value that was passed as an in-out argument".

struct MyStruct {
    var myStructsIntProperty: Int = 1

    mutating func myNotVeryThoughtThroughInoutFunction (inout myInt: Int) {
        myStructsIntProperty += 1
        /* What happens here? 'myInt' inout parameter is passed to this
           function by argument 'myStructsIntProperty' from _this_ instance
           of the MyStruct structure. Hence, we're trying to increase the
           value of the inout argument. Since the swift docs describe inout 
           as a "call by reference" type as well as a "copy-in-copy-out"
           method, this behaviour is somewhat undefined (at least avoidable).

           After the function has been called: will the value of
           myStructsIntProperty have been increased by 1 or 2? (answer: 1) */
        myInt += 1
    }

    func myInoutFunction (inout myInt: Int) {
        myInt += 1
    }
}

var a = MyStruct()
print(a.myStructsIntProperty) // 1
a.myInoutFunction(&a.myStructsIntProperty)
print(a.myStructsIntProperty) // 2
a.myNotVeryThoughtThroughInoutFunction(&a.myStructsIntProperty)
print(a.myStructsIntProperty) // 3 or 4? prints 3.

So, in this case, the inout behaves as copy-in-copy-out (and not by reference). We summarize by repeating the following statement from the language ref docs:

Do not depend on the behavioral differences between copy-in copy-out and call by reference.

Nolan Amy
  • 10,785
  • 5
  • 34
  • 45
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • I had trouble in understanding `Do not access the value that was passed as an in-out argument` statement, why is that, could you give an example? From what I understand, an argument, no matter inout or not, is first used to be accessed inside the function, otherwise we don't need the argument at all. – Wingzero Dec 28 '15 at 01:59
  • Sure, I'll add an example into the answer. – dfrib Dec 28 '15 at 02:02
  • This has to be the right answer. Thanks for the detailed comment. – nefarianblack May 28 '18 at 06:34
  • While an interesting experiment, this answer does not address the OP's only question: "What is a good use case for an inout parameter?" Also, Swift 5 will produce an error with the above code, preventing you from even entering a situation where you have competing/compounding by-ref and copy-in/copy-out value changes. – GtotheB Apr 01 '22 at 22:49
26

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

see image below for Description

Venu Gopal Tewari
  • 5,672
  • 42
  • 41
1

inout param: modifies passing and local variable values.

func doubleInPlace(number: inout Int) {
     number *= 2
     print(number) 
    
 }

 var myNum = 10 doubleInPlace(number: &myNum)
Sanjay Mali
  • 506
  • 6
  • 13
0

inout parameter allow us to change the data of a value type parameter and to keep changes still after the function call has finished.

H S W
  • 6,310
  • 4
  • 25
  • 36
0

If you work with classes then, as you say, you can modify the class because the parameter is a reference to the class. But this won't work when your parameter is a value type (https://docs.swift.org/swift-book/LanguageGuide/Functions.html - In-Out Parameters Section)

One good example of using inout is this one (defining math for CGPoints):

func + (left: CGPoint, right: CGPoint) -> CGPoint {
  return CGPoint(x: left.x + right.x, y: left.y + right.y)
}

func += (left: inout CGPoint, right: CGPoint) {
  left = left + right
}
abanet
  • 1,327
  • 17
  • 22
0

Basically it is useful when you want to play with addresses of variable its very useful in data structure algorithms

JeeVan TiWari
  • 325
  • 2
  • 15
0

when use inout parameter swift 4.0 Work

class ViewController: UIViewController {

    var total:Int = 100

    override func viewDidLoad() {
        super.viewDidLoad()
        self.paramTotal(total1: &total)
    }

    func paramTotal(total1 :inout Int) {
        total1 = 111
        print("Total1 ==> \(total1)")
        print("Total ==> \(total)")
    }
}
Pravin Parmar
  • 149
  • 1
  • 6