Inout

So far, we have only discussed pointers in terms of reference types. For the most part, this will work well, but sometimes you want something more flexible. This is where inouts come in.

Note that there are some pointer types like UnsafeMutablePointer UnsafeRawPointer, etc., but these are very advanced and not what we will be discussing. The only time I have seen them used is when I was playing around with graphics.

Background

For those unfamiliar with the idea of pointers:

When we think about our variables, we think about the values they hold. For example, if we say var x = 3 we think x being an Int of value 3. But, behind the scenes, x is actually a location in memory. At this current time, that location stores a value of 3, but if we were to assign a different value to x, the location would remain the same–we would just replace the value at the location.

If we think about our variables as locations instead of values, we have some interesting ramifications–this comes back to the reference Vs. value discussion layed out in classes Vs. structs. If we can find out where a value is stored in memory, we can pass that location to multiple locations and edit it from two places.

let id1: Int = <some location in memory of type Int>
var x = id1
var y = id1
x = 3
// y = 3

Note this is not valid code–it's just a demonstration of the concept.

This idea of passing a location, or to be more granular with terminology, a pointer to that location, is pretty prevalent in object-oriented languages.

Inout

OCaml programmers, think refs without dereferencing.

The most common time we want to use pointers in Swift is in functions. Otherwise, you can usually just access the variable. If you'll remember from functions, we can't simply modify the values in our parameters because they have been copied into let-constants. If we are dealing with reference types, you can, of course, just change its properties. But otherwise, we must explicitly tell the program that we want to preserve the location of the original variable with the inout label.

func changeMyInt(_ someInt: inout Int) {
    someInt += 1
}

Note that when we pass in an argument to this function, we must preserve it's location using a prefix &:

var myInt = 3
changeMyInt(&myInt)
// myInt: Int = 4

A great use for this is in static methods. The += operator needs to be able to get the value of a variable and assign to it. This means that its LHS parameter must be mutable!

To illustrate this, I will add += and ++ to the Integer class. += is already, but oh well ¯_(ツ)_/¯.

Okay, so +=. We need to make our LHS mutable _ lhs: inout Int, and take in an integer constant on the right side _ rhs: Int. Since we are assigning it to a variable, all of our changes will be stored in the LHS and we will not need to return anything. Thus, our function declaration should look like static func += (_ lhs: inout Int, _ rhs: Int). The rest is self-explanatory.

To do ++ we do the exact same process except we are operating on one parameter. This means our function will not be infix, so we must define it to either be prefix (before the parameter) or postfix (after the parameter).

extension Int {
    
    static func += (_ lhs: inout Int, _ rhs: Int) {
        lhs = lhs + rhs
    }
    
    static postfix func ++ (_ lhs: inout Int) {
        lhs += 1
    }
    
}

Note that since this is a unary/binary operator, we don't need to use the & to denote locations.

Last updated