Photo by Chu Son on Unsplash

Unsafe Swift: Understanding, usage, best practices and how to

Without any doubts Swift is one of the best safe programming language among many programming languages. The safety comes from powerful constructs like strong typing, type checking at compile time, optionals and few others.

A small amount of Swift Standard Library provides a collection of unsafe API’s. Before going into unsafe world let’s first understand what does a safe code means.

Safe Operations

A piece of code is safe when its behaviour is fully defined covering all cases of inputs. Let’s use the force unwrap of optionals as a trivial example to define what a safe code is

let first: Int? = 43
print(first!) // Prints 43

let second: Int? = nil
print(second!) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

In the first case the optional has a value and it executes correctly. In second case optional is nil and we get a runtime fatal error and code execution stops. This is a defined behaviour of optionals. This covers all the cases of input. In graphical form

Behaviour of safe force-unwrap of optional

Indeed force-unwrapping of optional is a severe programming error, but if we use it we have a well defined behaviour(i.e that our programme will crash).

Unsafe Operations

An unsafe operation is such that it will have undefined behaviour for at least one or more inputs that does not meet expectation of its documented input.

Optional also provides an unsafe force unwrapping operation. Similar to safe force-unwrap operation, unsafe operation required that underlying value to be non-nil. But if code is compiled using optimizations enabled, the unsafe operation does not verify the non-nil requirement, it proceeds with assumption that it contains a non-nil value. Let’s use optional from our last example to see an unsafe behaviour of force unwrap of optionals

let first: Int? = 43
print(first.unsafelyUnwrapped) // Prints 43

let second: Int?  = nil
print(second.unsafelyUnwrapped) // Undefined behaviour

In above example for first case the code execute nicely. While for second case we cannot reason what will happen when we are using an unsafe operation. There are many possibilities

Behaviour of unsafe force-unwrap of optional

It is important to note that there are many possibilities if we break the contract of an unsafe operation. In above example of unsafe force unwrap of optionals; if there is no value, it might give some garbage value back or we get a crash or something else. Also the behaviour may not be same when same code is run again.

The unsafe API does not verifies its requirements and assume that developer has full responsibility of its input i.e to have non-nil value for above example. However we got a helping hand from build tools here. In optimized build the unsafe force unwrap does not performs any non-nil value validation while it does performs validation in unoptimized debug builds.

In Swift standard library the unsafe API’s are prefixed with unsafe naming convention. This prefix will act as precaution to anyone reading or writing the code.

Another example: Unsafe Pointers

Let see another example of unsafe pointers.

let pointer = UnsafeMutablePointer<Int>.allocate(capacity: 1) // allocate the memory pointed by the pointer
pointer.initialize(to: 43) // Initialize the memory with some value
print(pointer.pointee) // Use the value
pointer.deallocate() // Deallocate the memory pointed by pointer. After this point the pointer becomes a dangling pointer
pointer.pointee // Any attempt to access the memory after deallocation then it will result in an undefined behaviour

It is important to note that pointer does not know anything about when it is allocated or deallocated. This is the responsibility of programmer to manage it. If we attempt to access the memory after deallocation then it will result in an undefined behaviour. Xcode provides us with a runtime debugging tool called Address Senitizer to help identify and fix this type of memory issues.

Benefits and usage of Unsafe API’s

The unsafe API’s can used to build code that is still reliable. There are mainly two main usage categories of unsafe API’s.

  1. Interoperability with C and Objective-C
  2. Fine grain control of performance at run time.

Unsafe Swift API’s are used for interoperability with other unsafe programming languages such as C or Objective-C. Lets consider a below C function that processes an int buffer in an array

void foo(const int* start, size_t count)

When this function is imported to Swift it will be in form

func foo(_ start: UnsafePointer<Int32>!, _ count: Int)

Note that the first const int pointer parameter is translated as unsafe implicitly unwrapped optional pointer type.

One of the way to call this C function from within Swift is as below

//1
let array = UnsafeMutablePointer<Int32>.allocate(capacity: 5)

//2
array.initialize(to: 23)
(array + 1).initialize(to: 54)
(array + 2).initialize(to: -43)
(array + 3).initialize(to: 0)
(array + 4).initialize(to: 13)

//3
foo(array, 5)

//4
array.deinitialize(count: 5)

//5
array.deallocate()

Below is discussion about each step and what is technically unsafe for each step.

  1. Use static allocate method of UnsafeMutablePointer to create a dynamic buffer to hold the integer values. Unsafe: Note that the lifetime of allocated buffer is not managed by the return pointer. We have to manage it ourself and manually deallocate it at some time otherwise it will stay in memory forever causing memory leak.
  2. Use pointer arthimetic to initialize array with some valid values. Unsafe: Initialization cannot automatically verify that calculated address is within memory range of buffer allocated. If we go out of range we will get an undefined behaviour.
  3. Unsafe: We are assuming that function is not going to take ownership of allocated buffer. This is by seeing the documentation of function or by looking into the implementation of function. The function will only access the buffer during its execution and does not hold on to memory or try to deallocate it .
  4. Unsafe: Deinitialization will only work if it was previously properly initialized with correct data type.
  5. Unsafe: We only deallocate a memory if it was previously allocated and is in deinitialized state.

At each step there are some unchecked assumptions and if we get any one of them wrong we will get an undefined behaviour.

There are two more issues with the above code

  1. The buffer is managed by its start address.
  2. Its length or size is in a separate value and that is scattered all over the code. In above case at least in three separate places.

The quality of code is greatly increased if we can somehow combine start address and size together. To address this Swift standard library provides below four pointer types.

  1. UnsafeBufferPointer<Element>
  2. UnsafeMutableBufferPointer<Element>
  3. UnsafeRawBufferPointer
  4. UnsafeMutableRawBufferPointer

These four buffer pointers are very helpful whenever we need to access the region of memory instead of pointer to individual elements. By combining region and size together these pointers will add some level of safety but developers are still in charge of managing the other aspects of safety. For unoptimized debug build these pointers check for out of bound access for subscript operations; thus having some safety.

Easy access to unsafe API’s in Swift Standard Collection

Some of the safety issues discussed in above example can be simplified by API’s provided by Swift standard collection library. These collection API’s provide an easy way to access their underlaying storage through simple unsafe methods.

Sequence.withContiguousStorageIfAvailable(_:)
MutableCollection.withContiguousMutableStorageIfAvailable(_:)

String.withCString(_:)
String.withUTF8(_:)

Array.withUnsafeBufferPointer(_:)
Array.withUnsafeMutableBufferPointer(_:)
Array.withUnsafeBytes(_:)
Array.withUnsafeMutableBytes(_:)

We can use above and few other methods to simplify our code and limit ourself to smallest number of unsafe code.

Taking our previous example and using the Swift Standard collection unsafe API’s, below will be new code

let array: [Int32] = [23, 54, -43, 0, 13]

array.withUnsafeBufferPointer { buffer in
    foo(buffer.baseAddress!, buffer.count) // The C function call
}

Notice how nicely we have avoided some of the unsafe operations and used only minimum needs unsafe calls. The unsafe operations that we have avoided are

  1. Unsafe static allocation
  2. Unsafe pointer arithematic to initialize
  3. Unsafe deinitialization
  4. Unsafe deallocation

We have only make an unsafe call to C function foo.

There is such a greater need to pass pointers to C functions such that Swift has special syntax to for it. We can simply pass array expecting an unsafe pointer and compiler will automatically generate the code equivalent for withUnsafeBufferPointer.

let array: [Int32] = [23, 54, -43, 0, 13]

foo(array, array.count) // The compiler will generate the code equivalent of withUnsafeBufferPointer 

An important point to remember is that the C function call is still unsafe.

Thank you for your time. If you liked the article please consider sharing it.

How to use Swift literals with custom types

Literals are combination of raw letters, characters and numbers that enable types to be constructed easily, below is a simple example of some common literals

let myString = "Hello World"
let myNumber = 34
let myDouble = 28.75

In above code example we have created three different variables using string, integer and double literals. In almost all programming languages there is support for literals and swift is of no difference. Swift even goes one step ahead, through use of its protocol oriented approach which allows any type to be able to initialise from literals.

Swift provides a set of protocols to work with literals as part of standard library here. All literal types from swift standard library can be divided into three different categories. Collection literals(arrays and dictionaries), value literals (int, float, bool and nil) and string literals.

Let’s consider a few examples how we can use swift initialisation with literals protocols to work with any custom type.

String Literals

struct Person {
    let firstName: String
    let lastName: String
}

Without using literal, an instance of above structure can be created as below

let person = Person(firstName: "Khurram", lastName: "Shehzad")

In order for our custom type to be able to initialize with literal we have to adopt to the literal protocol from which we want our custom type to be initialized from. For Person struct we will use ExpressibleByStringLiteral protocol to make it work with string literals.

struct Person: ExpressibleByStringLiteral {
    typealias StringLiteralType = String
    init(stringLiteral value: StringLiteralType) {
        let components = value.components(separatedBy: .whitespaces)
        firstName = components[0]
        lastName = components[1]
    }
    let firstName: String
    let lastName: String
}

Now we can easily create an instance of Person using string literal

let person: Person = "Khurram Shehzad"

Please note that we have explicitly mentioned the type. If we do not mention the type the swift compiler will use default type. For ExpressibleByStringLiteral the default type is String. Other protocols in for String literals are

Value Literals

Similarly we can have our custom types adopt to value literal as well. In the next example we have our custom type Temperature that is initialized from a Int value literal namely ExpressibleByIntegerLiteral

struct Temperature: ExpressibleByIntegerLiteral {
    typealias IntegerLiteralType = Int
    init(integerLiteral value: Int) {
        t = value
    }   
    let t: Int
}

let waterFreezing: Temperature = 0

Swift type inference system can work with literals when used with custom data types, as below

func waterBoilingTemperature() -> Temperature {
    return 100
}
let waterBoiling = waterBoilingTemperature() 

Note that swift type inference system will work here, as type is clearly evident from return type of function and we do not have a need to mention type explicitly at calling side.

Other protocols in value primitive literals are

Collection Literals

Swift standard library has also support for array and dictionary literals in ExpressibleByArrayLiteral and ExpressibleByDictionaryLiteral protocols respectively. Below is a simple example to use array literal.

class LinkedList: ExpressibleByArrayLiteral {
    var first: Node?
    class Node {
        var value: Int?
        var next: Node?
    }
    typealias ArrayLiteralElement = Int
    required init(arrayLiteral elements: Int...) {
        var current: Node?
        for element in elements {
            if first == nil {
                first = Node()
                first?.value = element
                current = first
            } else {
                let node = Node()
                node.value = element
                current?.next = node
                current = node
            }
        }
    }
}

let linkedList: LinkedList = [1, 2, 3, 4, 5]

Here we are initialising our custom linked list from swift array literal.

Similarly we can use ExpressibleByDictionaryLiteral for initialising from dictionary literal as well. Below is an example of utilising dictionary literal in custom type.

struct SolarSystem {
    struct Planet {
        let name: String
        let moonsCount: Int
    }
    let planets: [Planet]
}

extension SolarSystem: ExpressibleByDictionaryLiteral {
    typealias Key = String
    typealias Value = Int
    init(dictionaryLiteral elements: (String, Int)...) {
        var planets = [Planet]()
        for element in elements {
            planets.append(Planet(name: element.0, 
                                  moonsCount: element.1))
        }
        self.planets = planets
    }
}

let ourSolarSystem: SolarSystem = [
   "Mercury": 0, 
   "Venus": 0, 
   "Earth": 1, 
   "Mars": 2, 
   "Jupiter": 79, 
   "Saturn": 82, 
   "Uranus": 27, 
   "Neptune": 14]

For a complete list of available literals that you can use for you own custom types please see documentation here.

All the above code examples can be found here.

If you liked the article please consider sharing by using the share button below. Also please subscribe to mailing list to get latest updates immediately.

Atomic Types in Swift

In today modern apps multithreading is a de-facto standard for achieving concurrency. Multithreading comes with its own set of complexities i.e data race, dead lock, live lock etc. Apple provides various technologies for achieving multithreading on its platforms(macOS, iOS, iPadOS, watchOS and tvOS). These technologies include classic pthread, Thread(NSThread), NSOperationQueue and DispatchQueue.

One of the important aspect of multi threading is atomic types. Atomic types are language primitives that provide access to value with guarantee that no data race conditions arise.

Popular programming languages like C++ and Java have well established support for atomic types. C++ has std::atomic as part of standard library and Java has Atomic Variables as part of java.util.concurrent.atomic package.

Unfortunately as of writing there is no language support for atomic types in Swift. To demonstrate how an atomic type can be implemented in Swift we will start with a simple use case

// A protocol to be used in our atomic type
protocol Operatable {
    func add(other: Self) -> Self
}

final class Atomic<T: Operatable> {
    
    private var t: T
    
    init(_ t: T) {
        self.t = t
    }
    
    func incrementAndGet(by other: T) -> T {
        // Critical section starts
        // The change to t should be atomic here
        let result = t.add(other: other)
        t = result
        // Critical section ends
        return result
    }
}

In the above code snippet the implementation of incrementAndGet method is not thread safe. Below is our test code

// We will only use Int for our demo but it can be made to work with any other type
extension Int: Operatable {
    func add(other: Int) -> Int {
        return self + other
    }
}

func test() {
    let atomicInt = Atomic<Int>(0)
    for i in 1...5 {
        let thread = Thread {
            print("\(Thread.current.name!):Value:\(atomicInt.incrementAndGet(by: 1))")
        }
        thread.name = "Thread: \(i)"
        thread.start()
    }
    Thread.sleep(forTimeInterval: 2)
}

Below is one of the possible output of above test code

Thread: 4: critical section started
Thread: 5: critical section started
Thread: 2: critical section started
Thread: 3: critical section started
Thread: 4: critical section ended
Thread: 5: critical section ended
Thread: 2: critical section ended
Thread: 1: critical section started
Thread: 3: critical section ended
Thread: 1: critical section ended

The is exactly the behaviour we do not want. What we want is at any given time there will at most one thread in critical section, thus it will make our type atomic. In below sections we will discuss various approaches to make the Atomic class truly atomic.

Using NSLock

We can achieve atomicity using NSLock from Foundation framework. Below is a simple implementation of Atomic class using NSLock.

final class NSAtomic<T: Operatable> {
    
    private var t: T
    private let lock = NSLock()
    init(_ t: T) {
        self.t = t
    }
    
    func incrementAndGet(by other: T) -> T {
        // Critical section starts
        // The change to t should be atomic here
        lock.lock()
        print("\(Thread.current.name!): critical section started")
        let result = t.add(other: other)
        t = result
        print("\(Thread.current.name!): critical section ended")
        lock.unlock()
        // Critical section ends
        return result
    }
}

func testNSAtomic() {
    print("test with NSLock")
    let atomicInt = NSAtomic<Int>(0)
    for i in 1...5 {
        let thread = Thread {
            _ = atomicInt.incrementAndGet(by: 1)
        }
        thread.name = "Thread: \(i)"
        thread.start()
    }
    Thread.sleep(forTimeInterval: 2)
}

We have just added a NSLock instance variable to our atomic type. Below is the output of using our NSAtomic class.

Thread: 1: critical section started
Thread: 1: critical section ended
Thread: 2: critical section started
Thread: 2: critical section ended
Thread: 3: critical section started
Thread: 3: critical section ended
Thread: 4: critical section started
Thread: 4: critical section ended
Thread: 5: critical section started
Thread: 5: critical section ended

The is the correct behaviour we want. Each thread wait outside critical section if there is another thread currently inside critical section. We have ensured that our value t is only changed by only one thread at any given time.

Using Grand Central Dispatch (GCD)

Using GCD is Apple recommended way of achieving concurrency. We will modify our Atomic class and implement it using a serial dispatch queue.

final class GCDAtomic<T: Operatable> {
    
    private let initial: T
    private var t: T
    private let dispatchQueue = DispatchQueue(label: "tech.swiftx.dispatchQueue")
    init(_ t: T) {
        self.t = t
        initial = t
    }
    
    func incrementAndGet(by other: T) -> T {
        
        var result = initial
        dispatchQueue.sync {
            // Critical section starts
            // The change to t should be atomic here
         
            print("\(Thread.current.name!): critical section started")
            result = t.add(other: other)
            t = result
            print("\(Thread.current.name!): critical section ended")
            
            // Critical section ends
        }
        return result
    }
}

Below is the output of using GCDAtomic class

Thread: 1: critical section started
Thread: 1: critical section ended
Thread: 5: critical section started
Thread: 5: critical section ended
Thread: 3: critical section started
Thread: 3: critical section ended
Thread: 4: critical section started
Thread: 4: critical section ended
Thread: 2: critical section started
Thread: 2: critical section ended

Please note that the order of thread execution is not relevant. The important factor is that at any give time only one of the thread is executing in critical section. This has also same behaviour as using NSLock.

All the above code snippets can be found here.

This a lot of boilerplate code. Luckily you dont have to implement atomic behaviour from scratch for your swift project. There is a popular open source library for working with atomics types in swift named swift-atomics.(I am not associated with swift-atomics library).

Towards Native Swift Atomics

As of writing there is a proposal SE-0282 in swift evolution that promises atomic types in swift as part of swift standard library. If the proposal is accepted we will see first class atomic types in swift in future swift versions.

Important Links

NSLock: https://developer.apple.com/documentation/foundation/nslock

GCD: https://developer.apple.com/documentation/DISPATCH

Swift-atomics: https://github.com/glessard/swift-atomics

SE-0283: https://github.com/apple/swift-evolution/blob/master/proposals/0282-atomics.md

Gist: https://bit.ly/3gD9QV6

std::atomic: https://en.cppreference.com/w/cpp/atomic/atomic

java.util.concurrent.atomic: https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html

If you liked the article please consider sharing it with other people. Also please subscribe to my mailing list to get latest updates immediately.