What does an ampersand (&) mean in the Swift language?

SwiftAmpersandInout

Swift Problem Overview


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?

Swift Solutions


Solution 1 - Swift

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.

I hope that helps you!

Solution 2 - Swift

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

Solution 3 - Swift

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

Solution 4 - Swift

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.

Solution 5 - Swift

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionapplejuiceteachingView Question on Stackoverflow
Solution 1 - SwiftIcaroView Answer on Stackoverflow
Solution 2 - SwiftLeoView Answer on Stackoverflow
Solution 3 - SwiftWilliam KinaanView Answer on Stackoverflow
Solution 4 - SwiftWongWrayView Answer on Stackoverflow
Solution 5 - SwiftricksterView Answer on Stackoverflow