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

5

77

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?

Epigraphy answered 30/5, 2015 at 1:22 Comment(1)
Check In-Out Parameters in the Swift Functions documentationCsc
M
92

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.

Mulford answered 30/5, 2015 at 1:27 Comment(5)
It can also be used for calling C APIs from Swift with the traditional C meaning of the "address of" a variable. In Swift this takes the form of UnsafePointer<Type>. So for example in Swift a C API expecting a pointer might take a parameter of UnsafePointer<CGFloat> and you could call it with &myCGFloat. (developer.apple.com/library/ios/documentation/Swift/Conceptual/…)Nkrumah
I don't understand why it's necessary since the message signature already specifies that it is inout. Why do it twice?Nels
@Nels - I think the rationale for making programmers mark both the parameter (inout) and argument (&) as a reference is to make it clear to callers, who may not be aware of the function definition, that the arguments are references and could be mutated, thus avoiding bugs that would otherwise occur from variables being unexpectedly changed.Bish
I understand the inout functionality but What does that mean return sum & 0xffLynnlynna
@MoosaBaloch in that context the & is a bitwise AND operatorExclamation
B
23

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.

Bagwig answered 21/5, 2020 at 19:52 Comment(2)
The question is specifically about Ampersand in front of variables not between protocols...Analysand
It doesn't relate to the question but this is what I'm looking for so thank you!Cofferdam
T
22

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
Taxicab answered 30/5, 2015 at 1:25 Comment(2)
and what's the alternative situation your example? I mean if you had done add(temp) what how would it be different? would temp be 10?Kwiatkowski
++ deprecated O:-)Dorty
E
13

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
Enteric answered 5/10, 2015 at 11:14 Comment(0)
S
6

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.

Sextuple answered 19/9, 2016 at 22:2 Comment(2)
Wow, thank you for an extremely comprehensive and enlightening explanation! I wasn't aware of these subtle behaviors of the ampersand operator in swift.Spoilsport
My biggest problem with talking about inout is it makes me want to head down the street for a double-double and a milkshake.Sextuple

© 2022 - 2024 — McMap. All rights reserved.