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?
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).
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:
Using inout keyword: is the parameter passed-by-reference or by copy-in copy-out (/call by value result)
(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.
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.
inout param: modifies passing and local variable values.
func doubleInPlace(number: inout Int) {
number *= 2
print(number)
}
var myNum = 10 doubleInPlace(number: &myNum)
inout parameter allow us to change the data of a value type parameter and to keep changes still after the function call has finished.
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
}
Basically it is useful when you want to play with addresses of variable its very useful in data structure algorithms
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)")
}
}
Related
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?
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).
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:
Using inout keyword: is the parameter passed-by-reference or by copy-in copy-out (/call by value result)
(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.
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.
inout param: modifies passing and local variable values.
func doubleInPlace(number: inout Int) {
number *= 2
print(number)
}
var myNum = 10 doubleInPlace(number: &myNum)
inout parameter allow us to change the data of a value type parameter and to keep changes still after the function call has finished.
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
}
Basically it is useful when you want to play with addresses of variable its very useful in data structure algorithms
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)")
}
}
If i run the following code in XCode 12 playground (Swift 5.3) I get the same result from two listings:
import Foundation
var dict = NSMutableDictionary()
dict["x"] = 42
func stuff(_ d: inout NSMutableDictionary) {
d["x"] = 75
}
stuff(&dict)
dump(dict) // x is 75
the other:
import Foundation
var dict = NSMutableDictionary()
dict["x"] = 42
func stuff(_ d: NSMutableDictionary) {
d["x"] = 75
}
stuff(dict)
dump(dict) // x is 75 still
As per the documentation here, the second listing should give me an error:
https://docs.swift.org/swift-book/LanguageGuide/Functions.html
But it works anyway.
Is this because the enforcement of these in-out rules is constrained to Swift only types, and Cocoa types are exempt?
This works not because Cocoa types are exempt, but because NSMutableDictionary is a class (as opposed to a struct), and the inout does not refer to what you might be thinking.
Unfortunately, the documentation you link to (and the more in-depth documentation on inout parameters it links to) doesn't make it clear what "value" really means:
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value
The following statement hints at it a little, but could be clearer:
You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified.
The "value" the documentation describes is the variable being passed as inout. For value types (structs), this is meaningful because every variable holding a value of those types effectively holds a copy of that value.
var a = MyGreatStruct(...)
var b = a
// a and b are not directly linked in any way
Passing a struct to a function normally copies the value into a new local variable (new variable = copy), whereas you can imagine inout giving you direct access to the original variable (no new variable).
What's not described is that the effect is identical for classes, which behave differently.
let a = MyGreatClass(...)
let b = a
// modifying `a` will modify `b` too since both point to the same instance
Passing a class to a function also copies the variable into a new local variable, but the copy isn't meaningful — both variables hold the same thing: a reference to the object itself in memory. Copying in that sense doesn't do anything special, and you can modify the object from inside of the function the same way you could from outside. inout for classes behaves the same way as for structs: it passes the original variable in by reference. This has no bearing on the majority of the operations you'd want to perform on the object anyway (though it does allow you to make the variable point to a different object from within the function):
var a = MyGreatClass("Foo")
// func foo(_ value: MyGreatClass) {
// value = MyGreatClass("Bar") // <- not allowed since `value` isn't mutable
// }
func foo(_ value: inout MyGreatClass) {
value = MyGreatClass("Bar")
}
print(ObjectIdentifier(a)) // <some pointer>
foo(&a)
print(ObjectIdentifier(a)) // <some other pointer>
I have a question according usage of the inout in Swift 3.
As i understand inout is quite expensive operation for use.
And there is question when and why it is better to use inout declaration?
regular function:
func double(input: Int) {
var input = input
input = input * 2
}
inout declaration use:
func double(input: inout Int) {
input = input * 2
}
Be careful, this is a classic trap! :)
Your two functions are not doing the same thing, so one is not "better" than the other.
Your first one:
func double(input: Int) {
var input = input
input = input * 2
}
does nothing.
Because with var input = input you are making a copy of the input value, so when you do input = input * 2 you are just modifying the local copy, and since you don't return it, it is discarded and this function has no effect in the end.
Your second one:
func double(input: inout Int) {
input = input * 2
}
does something: it modifies the original value because inout is a way of passing a value by reference. No need to make a copy and return it: the variable itself, the one you pass to the function, will be changed.
Note: I suggest you read Martin R's excellent link where inout is very well explained: https://stackoverflow.com/a/34486250/1187415.
I know about the ampersand as a bit operation but sometimes I see it in front of variable names. What does putting an & in front of variables do?
It works as an inout to make the variable an in-out parameter. In-out means in fact passing value by reference, not by value. And it requires not only to accept value by reference, by also to pass it by reference, so pass it with & - foo(&myVar) instead of just foo(myVar)
As you see you can use that in error handing in Swift where you have to create an error reference and pass it to the function using & the function will populate the error value if an error occur or pass the variable back as it was before
Why do we use it? Sometimes a function already returns other values and just returning another one (like an error) would be confusing, so we pass it as an inout. Other times we want the values to be populated by the function so we don't have to iterate over lots of return values, since the function already did it for us - among other possible uses.
It means that it is an in-out variable. You can do something directly with that variable. It is passed by address, not as a copy.
For example:
var temp = 10
func add(inout a: Int){
a++
}
add(inout:&temp)
temp // 11
There's another function of the ampersand in the Swift language that hasn't been mentioned yet. Take the following example:
protocol Foo {}
protocol Bar {}
func myMethod(myVar: Foo & Bar) {
// Do something
}
Here the ampersand syntax is stating that myVar conforms to both the Foo and Bar protocol.
As another use case, consider the following:
func myMethod() -> UIViewController & UITableViewDataSource {
// Do something
}
Here we're saying that the method returns a class instance (of UIViewController) that conforms to a certain protocol (UITableViewDataSource). This is rendered somewhat obsolete with Swift 5.1's Opaque Types but you may see this syntax in pre-Swift 5.1 code from time to time.
If you put & before a variable in a function, that means this variable is inout variable.
#Icaro already described what it means, I will just give an example to illustrate the difference between inout variables and in variables:
func majec(inout xValue:Int, var yValue:Int) {
xValue = 100
yValue = 200
}
var xValue = 33
var yValue = 33
majec(&xValue, yValue: yValue)
xValue //100
yValue //33
As noted in other answers, you use prefix & to pass a value to an inout parameter of a method or function call, as documented under Functions > Function Argument Labels and Parameter Names > In-Out Parameters in The Swift Programming Language. But there's more to it than that.
You can, in practice, think about Swift inout parameters and passing values to them as being similar to C or C++ pass-by-address or pass-by-reference. In fact, the compiler will optimize many uses of inout parameters down to roughly the same mechanics (especially when you're calling imported C or ObjC APIs that deal in pointers). However, those are just optimizations — at a semantic level, inout really doesn't pass addresses around, which frees the compiler to make this language construct more flexible and powerful.
For example, here's a struct that uses a common strategy for validating access to one of its properties:
struct Point {
private var _x: Int
var x: Int {
get {
print("get x: \(_x)")
return _x
}
set {
print("set x: \(newValue)")
_x = newValue
}
}
// ... same for y ...
init(x: Int, y: Int) { self._x = x; self._y = y }
}
(In "real" code, the getter and setter for x could do things like enforcing minimum/maximum values. Or x could do other computed-property tricks, like talking to a SQL database under the hood. Here we just instrument the call and get/set the underlying private property.)
Now, what happens when we pass x to an inout parameter?
func plusOne(num: inout Int) {
num += 1
}
var pt = Point(x: 0, y: 1)
plusOne(num: &pt.x)
// prints:
// get x: 0
// set x: 1
So, even though x is a computed property, passing it "by reference" using an inout parameter works the same as you'd expect it to if x were a stored property or a local variable.
This means that you can pass all sorts of things "by reference" that you couldn't even consider in C/C++/ObjC. For example, consider the standard library swap function, that takes any two... "things" and switches their values:
var a = 1, b = 2
swap(&a, &b)
print(a, b) // -> 2 1
var dict = [ "Malcolm": "Captain", "Kaylee": "Mechanic" ]
swap(&dict["Malcolm"], &dict["Kaylee"])
print(dict) // -> ["Kaylee": "Captain", "Malcolm": "Mechanic"], fanfic ahoy
let window1 = NSWindow()
let window2 = NSWindow()
window1.title = "window 1"
window2.title = "window 2"
var windows = [window1, window2]
swap(&windows[0], &windows[1])
print(windows.map { $0.title }) // -> ["window 2", "window 1"]
The the way inout works also lets you do fun stuff like using the += operator on nested call chains:
window.frame.origin.x += 10
... which is a whole lot simpler than decomposing a CGRect just to construct a new one with a different x coordinate.
This more nuanced version of the inout behavior, called "call by value result", and the ways it can optimize down to C-style "pass by address" behavior, is covered under Declarations > Functions > In-Out Parameters in The Swift Programming Language.
I decided to update a project that I had made during Swift beta 1 now that Swift 1.0 is out. There's a particular issue, however, that I can't seem to fix that came up as a result of the updated array semantics and inout keyword. Consider the following two functions (you can just paste them into a playground):
func bubbleSort<T : Comparable>(inout arr : [T]) {
var numSwaps = 0
do {
numSwaps = 0
for i in 0..<(arr.count - 1) {
if arr[i] > arr[i + 1] {
(arr[i], arr[i + 1]) = (arr[i + 1], arr[i])
numSwaps++
}
}
} while numSwaps != 0
}
func testFunc(sortFunc: ([Int]) -> ()) {
sortFunc([5,4,3,2,1])
}
I can't seem to make the two work together. I tried using shorthand:
testFunc {bubbleSort(&$0)}
I also tried without shorthand:
testFunc { (arr: [Int]) -> () in
bubbleSort(&arr)
}
In either case, I get errors:
Is this a bug, or am I screwing something up? Thanks in advance!
What you're running into is that method parameters are by default immutable and in-out functions are mutating. You can't use the closure shorthand, because you'll need to declare the closure's argument as mutable with the var keyword, like so:
func testFunc(sortFunc: ([Int]) -> ()) {
sortFunc([5,4,3,2,1])
}
testFunc { (var arr: [Int]) -> () in
bubbleSort(&arr)
}
Now you can call bubbleSort with arr as the in-out parameter.
What you're running into is the change in beta 3 (if I recall correctly) where changing en element of an array became a mutating operation. Before that changing an element was a non-mutating operation, and therefore you can change an element on an Array constant; you just couldn't change its length. But since beta 3, to change an element on an array, it needs to be non-constant.
bubbleSort takes the array by reference (inout) because it needs to change the elements of the array and have it visible to the caller (prior to beta 3, it just took it by value). You can only pass a non-constant variable by reference. In the closure you wrote, arr is a constant (it's an array parameter not declared var or inout), therefore you cannot pass it by reference.
The obvious answer is that arr needs to be var or inout. Which one you need depends on what these functions are intended to do. What you have currently is discard the result of calls, which is pointless, so you are clearly not showing us what these functions are supposed to do.
#NakeCook's answer, simply make arr a var, makes it possible to pass it by reference, but it doesn't change the fact that the closure takes its argument by value (and the fact that sortFunc in testFunc is a pass-by-value function. That means testFunc gives an array to the function to sort, but does not care or want changes to be reflected back to it. If this is what you want, then that is the answer.
However, if testFunc is supposed to have an array, pass it to a sort function to sort, and wants to see changes to the array in its scope, then it needs to do something else:
func testFunc(sortFunc: (inout [Int]) -> ()) {
var x = [5,4,3,2,1]
sortFunc(&x)
}
testFunc { (inout arr: [Int]) -> () in
bubbleSort(&arr)
}
In this case, the closure's parameter is declared as inout (so it's passed by reference), and also the sortFunc (in testFunc)'s type explicitly mentions that it takes its parameter by reference.