4thSpace
4thSpace

Reputation: 44312

When to use inout parameters?

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?

Upvotes: 86

Views: 52700

Answers (8)

Sanjay Mali
Sanjay Mali

Reputation: 546

inout param: modifies passing and local variable values.

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

 var myNum = 10 doubleInPlace(number: &myNum)

Upvotes: 1

Pravin Parmar
Pravin Parmar

Reputation: 159

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)")
    }
}

Upvotes: 0

JeeVan TiWari
JeeVan TiWari

Reputation: 335

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

Upvotes: 0

abanet
abanet

Reputation: 1387

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
}

Upvotes: 0

dfrib
dfrib

Reputation: 73186

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.

Upvotes: 48

H S W
H S W

Reputation: 7119

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

Upvotes: 0

Lucas Huang
Lucas Huang

Reputation: 4016

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).

Upvotes: 136

Venu Gopal Tewari
Venu Gopal Tewari

Reputation: 5876

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

Upvotes: 26

Related Questions