Archive for the ‘Swift’ Category

The problem with Swift Playground localization

Starting in Swift Playgrounds 2, you can now use localized strings to guide the narration of your interactive lessons. As the screenshot above demonstrates, you can used localizable markup to provide the most appropriate text for titles, introductory text, and feedback.

However, what you can’t do is localize Swift members. Your French and Chinese consumers must tell Byte to moveForward(), not avancer() or 向前移动().

One of the guiding principles of the Swift language is demonstrated in its embrace of unicode for identifier symbols. This approach accommodates programmers and programming styles from many languages and cultures.

Xcode 9 has introduced major advances in code refactoring. It seems an obvious win to allow that technology to be applied to Swift Playgrounds 2, enabling identifier localization.

That’s because identifiers play such a key role in Swift Playgrounds. Unlike standard development tasks, where it’s unnecessary to create idiomatic APIs like IUContrôleurDeNavigation, the point of Swift Playgrounds is to teach and instruct. It uses small, limited, controlled API exposure, nearly all custom and supporting of the teaching story.

The anthropomorphized Byte character acts as a stand-in for the learner coder. And in doing so, it should communicate with commands that this coder identifies with, turnLeft and moveForward, not incomprehensibleForeignPhrase1 and evenMoreConfusingForeignPhrase2.

I think this is an opportunity waiting to happen, and I can’t imagine it would be all that hard to implement given the expansive identifier suite and the limited API visibility presented in a typical playgroundBook.

What do you think? Is it too much to ask for a localizable.Members.plist?

State of the Swift PM from the Swift PM PM

From Rick Ballard, Swift Package Manager release manager, a status update with regard to Swift 4. Here’s an overview of the proposals that have recently been incorporated into the system:

We’ve implemented a number of evolution proposal[s] this Spring:

• SE-0152 [ https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md ] introduced a “tools version”, stored in a comment at the top of the Package.swift manifest, which allows you to declare what version of the Swift tools your package requires, and to avoid resolving package dependencies against package versions which require newer tools than those you are using. The tools version is also used to control whether to enable new features such as the revised package manifest API, and to determine which Swift language version is used to interpret the manifest.

• SE-0158 [ https://github.com/apple/swift-evolution/blob/master/proposals/0158-package-manager-manifest-api-redesign.md ] redesigned the Package manifest API, adopting the Swift API design guidelines and cleaning up some problems in our API. Existing packages can continue to use the old Package manifest API until they update their Swift tools version.

• SE-0151 [ https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md ] introduced a property to control which Swift language version should be used to compile a package’s sources. If this property is not set, the default is determined by the package’s Swift tools version.

• SE-0146 [ https://github.com/apple/swift-evolution/blob/master/proposals/0146-package-manager-product-definitions.md ] added explicit control over what products a package vends to clients, and what targets are used to build each product. Packages using the new manifest API must declare any products which they wish their package to vend.

• SE-0175 [ https://github.com/apple/swift-evolution/blob/master/proposals/0175-package-manager-revised-dependency-resolution.md ] removed the conditional “pinning” feature and replaced it with a simpler “resolved package versions” file (“Package.resolved”), along with improvements to SwiftPM’s dependency resolution behaviors.

• SE-0150 [ https://github.com/apple/swift-evolution/blob/master/proposals/0150-package-manager-branch-support.md ] added support for packages which depend on a branch, rather than a tagged version, of other packages. This is especially useful during bringup of a new package, and in-between tagged releases. In order to enforce stability for tagged versions, a tagged package version must only depend on other packages’ tagged versions, not on branches.

• SE-0162 [ https://github.com/apple/swift-evolution/blob/master/proposals/0162-package-manager-custom-target-layouts.md ] added API for controlling where the source files for each target should be found. This allows SwiftPM to support source trees that don’t conform to the standard package layout conventions.

• SE-0149 [ https://github.com/apple/swift-evolution/blob/master/proposals/0149-package-manager-top-of-tree.md ] added support for a “–path” flag to `swift package edit`, allowing users to take full control over an edited dependency and share it between multiple top-level packages.

In addition to these proposals, we’ve made other significant improvements:

• On macOS, package manifest interpretation and the package build are now sandboxed, to help mitigate the effects of maliciously crafted manifests.

• Many error messages and diagnostics have been improved, including information about conflicts during dependency resolution.

• Xcode project generation has been improved, and now allows schemes to reference package targets across regenerations of the project.

• There have been a host of smaller improvements and bugfixes.

All these changes are available in the Xcode 9 beta released today, and in the Swift 4.0 Development snapshots available at https://swift.org/download/#snapshots.

Xcode 9 lays the groundwork for first-class, native support in Xcode for Swift packages with the preview version of its new build system. This build system provides the flexibility and extensibility needed to allow Xcode to support new build models, such as Swift packages. Additionally, considerable work has gone into the SwiftPM library vended by the SwiftPM project, which will support integrating Swift packages into tools like Xcode.

So what’s left in SwiftPM 4? First, we will be implementing SE-0179 [ https://github.com/apple/swift-evolution/blob/master/proposals/0179-swift-run-command.md ], support for a `swift package run` command. Beyond that, we expect to start winding down this release and looking ahead to the next, though we are still open to suggestions or evolution proposals for modest features and fixes.

There are a few features that we originally considered for SwiftPM 4 which are unlikely to be included in this release at this point: performance test support, support for configuration files, support for repositories which contain more than one package, and build settings support. With the possible exception of configuration files, these are likely to be a high priority for the next release. In particular, the core team has done work on a design for build settings which we expect to invite comment and discussion on early in the next release; this is a fairly consequential feature, and we want to make sure to get it right. Since that feature is not landing in SwiftPM 4, we are considering adding some package properties in SwiftPM 4 that will help alleviate some of the biggest pain points here, such as a C++ language version property.

Other features we will likely consider for the next release cycle include support for package resources (such as image assets), license and metadata support, explicit support for handling source control forking, and a generic mechanism for invoking build tools that the package manager doesn’t natively support. Finally, we do anticipate supporting a centralized package index at some point in the future, and we may begin laying the groundwork for that in the upcoming year.

As always, we appreciate the support, feedback, contributions, and adoption we’ve gotten from the package manager community. We’re looking forward to working with you all over the upcoming year to make SwiftPM even better.

Apple open sources key file-level transformation Xcode components

Ted Kremenek writes on the swift-dev list:

This afternoon at WWDC we announced a new refactoring feature in Xcode 9 that supports Swift, C, Objective-C, and C++.  We also announced we will be open sourcing the key parts of the engine that support file-level transformations, as well as the compiler pieces for the new index-while-building feature in Xcode.

We will be releasing the sources in stages, likely over the next few weeks:

– For the refactoring support for Swift, there are some cleanups we’d like to do as well as some documentation we’d like to author before we push these sources back.  Argyrios Kyrtzidis and his team from Apple will be handling that effort.

– For the refactoring support for C/C++/Objective-C, these are changes we’d like to work with the LLVM community to upstream to the LLVM project.  These will likely be first staged to the swift-clang repository on GitHub, but that is not their intended final destination.  Duncan Exon Smith and his team from Apple will be handling that effort.

– We’ll also be open sourcing the compiler support for indexing-while-building, which include changes to both Clang and Swift.   Argyrios and his team will be driving that effort.  For the clang changes they will likely be first staged to swift-clang, and then discussed with the LLVM community to upstream them to mainline Clang.

– Finally, we will be open sourcing the remaining pieces of the Swift migrator.  Argyrios and his team will be handling the push back of changes there, and those changes will only be impacting the swift repository.

As usually, we’ll also be pushing back changes to have Swift work with the latest Apple SDKs.  We’re expecting that push back to happen early next week.  When that happens we will temporarily lock commit access to the repositories.  Details about that will be sent out later in a later email.  Until then, the downloadable toolchains from Swift.org will continue to work with Xcode 8.3.2.  After we do the push back the downloadable toolchains will be moved to be baselined on the Xcode 9.0 betas.  This shift is necessary as changes to the overlays depend on the latest SDKs.

Writing a binary search tree

Tim discusses using Swift enumeration indirect keywords to build binary tree nodes. Read on to learn more about how reference types and value semantics combine…

Today we’re writing a simple binary search tree in Swift. While binary search trees seem to be very powerful in theory, their performance is rather disappointing in practice. Other, more advanced tree-shaped data structures such as red-black trees and B-trees solve some of the practical problems that binary search trees have, and are subsequently much more useful in performance-critical code. Nevertheless, learning about binary search trees is the first step to getting more familiar with this class of data structures.

Probably the simplest way to represent a binary tree in Swift is by using an indirect enum, like so:

enum BinarySearchTree<Element: Comparable> {
    case empty
    indirect case node(left: BinarySearchTree, value: Element, right: BinarySearchTree)
}

While indirect enums use reference types under the hood, they have value semantics by default. So that’s nice.

From all the standard library’s protocols, SetAlgebra and BidirectionalCollection both seem a good fit for our BinarySearchTree type: SetAlgebra for inserting and removing elements, and BidirectionalCollection for traversing the tree (both forwards and backwards, hence the name). However, for the purpose of this post, we’ll stick to only a couple basic methods.

Let’s start with insertion. Because of the way enums with associated values work, it’s easiest to implement the insert method using an under-the-hood inserting method:

extension BinarySearchTree {
    mutating func insert(_ element: Element) {
        self = inserting(element)
    }
    
    private func inserting(_ element: Element) -> BinarySearchTree {
        switch self {
        case .empty:
            // the tree is empty, so inserting an element results in a tree containing only that element
            return .node(.empty, element, .empty)
            
        case .node(_, element, _):
            // the element is already present in the tree
            return self
            
        case let .node(left, value, right) where element < value:
            // the element should be inserted into the left subtree
            return .node(left.inserting(element), value, right)
            
        case let .node(left, value, right):
            // the element should be inserted into the right subtree
            return .node(left, value, right.inserting(element))
        }
    }
}

Now we can insert values into a tree, but we can’t read them in any way. So let’s add a contains method as well:

extension BinarySearchTree {
    func contains(_ element: Element) -> Bool {
        switch self {
        case .empty:
            // an empty tree obviously doesn't contain any elements!
            return false
            
        case .node(_, element, _):
            // the element is equal to this node's value
            return true
            
        case let .node(left, value, _) where element < value:
            // if the element is present in the tree, it must be in the left subtree
            return left.contains(element)
            
        case let .node(_, _, right):
            // if the element is present in the tree, it must be in the right subtree
            return right.contains(element)
        }
    }
}

Let’s try it out!

var tree = BinarySearchTree.empty

tree.contains(5) // => false
tree.insert(5)
tree.contains(5) // => true
tree.insert(3)
tree.contains(3) // => true
tree.contains(5) // => true

Looks good. We can’t actually remove elements, though, but that is a real pain to implement and it’s out of scope for this post.

Finally, to iterate over a binary search tree, we need to implement the IteratorProtocol protocol. We’ll use an in-order traversal algorithm:

extension BinarySearchTree: Sequence {
    func makeIterator() -> BinarySearchTreeIterator<Element> {
        return BinarySearchTreeIterator(self)
    }
}

struct BinarySearchTreeIterator<Element: Comparable>: IteratorProtocol {
    var node: BinarySearchTree
    var stack: [(Element, BinarySearchTree)] = []
    
    init(_ node: BinarySearchTree) {
        self.node = node
    }
    
    public mutating func next() -> Element? {
        while case let .node(left, value, right) = node {
            stack.append((value, right))
            node = left
        }
        
        guard let (element, node) = stack.popLast() else { return nil }
        
        self.node = node
        return element
    }
}

Now we can do all kinds of sequence-y stuff with trees, like so:

var tree = BinarySearchTree.empty
[5, 2, 4, 8, 3, 2].forEach { tree.insert($0) }

for element in tree {
    print(element, terminator: " ") // => 2 3 4 5 8
}

tree.reduce(0, +)                                  // => 22
tree.lazy.map(String.init).joined(separator: ", ") // => 2, 3, 4, 5, 8

And the list goes on.

That’s it for now! If you enjoy this kind of stuff, make sure to check out Károly Lőrentey’s brand new book Optimizing Collections in which he in much detail goes through implementing several data structures in Swift, focusing on performance. As of writing this post, it’s 25% off.

Erica Knows Nothing About Kotlin: Kotlin collections

Cocoa distinguishes NSArray from NSMutableArray, among many other mutable variations on standard types. In Swift, you var or let a collection and let the compiler handle the rest of the details, whether the outcome is mutable or not. Kotlin follows the Cocoa model. It uses distinct collection types based on mutability.

For example, the listOf function returns a new read-only serializable list of elements.

val myList: List<Double> = listOf(1.0, 2.0, 3.0)

You cannot automatically promote typeless literals the way you can in Swift. In Swift the literal “1” doesn’t have an intrinsic type (although it defaults to Int in the absence of any other context). “1” can represent an integer, a double, a float, and more.

Kotlin does not support literal inference. If you use listOf(1, 2, 3) for the preceding example, Kotlin issues an error: “Type inference failed. Expected type mismatch: inferred type is List<Int> but List<Double> was expected”.

Like Swift, Kotlin’s type inference system permits you to drop the explicit List<Double> type annotation from the myList declaration.  The listOf function still produces the expected type, which the compiler assigns to the constant myList. In this declaration, Kotlin’s val is the same as Swift’s let. It produces a constant rather than a (var) variable.

However, the list you produced is not a value type. Switch the list from immutable to mutable, and you’ll still (like an NSMutableArray reference) be able to add new members:

val myList: MutableList<Double> = mutableListOf(1.0, 2.0, 3.0)
myList.add(4.0)
println(myList) // [1.0, 2.0, 3.0, 4.0]

You won’t be able to re-assign myList to a new list, but as a mutable reference type, the underlying instance can be modified because it is a MutableList<T>.

Kotlin also offers dictionaries, which it calls maps. That’s really not a bad name for a type that performs one-to-one mapping, which is all that key-value lookup really does. The underlying types honor that key/value relation. They’re called Map<K, out V> and MutableMap<K, V>.

val myDictionary = mutableMapOf(
    "cow" to "moo",
    "dog" to "woof",
    "pig" to "oink"
)

println(myDictionary["dog"]) // woof
println(myDictionary["kitten"]) // null

Like Swift, Kotlin returns a “not there” result for a failed map lookup, but the meaning of null is distinct from Swift’s nil. A type must be nullable (sort of but not entirely like Optional) to store a null reference.

var string = "Hello"
println(string)
// string = null 
// error: null can not be a value of a non-null type String

var string2: String? = "Hello"
println(string2) // hello
string2 = null
println(string2) // null

The initial value of string2 is not Optional("hello") or something like that. It feels (at least so far, because I know nothing about Kotlin, see the title of this post) more like the Objective-C nil, that is a null-reference in memory rather than a pointer to a reference type. I’m new to this, so I’m still learning.

Speaking of null, the first string example demonstrates what happens when you assign null to a non-nullable type. You end up with a (more or less) null pointer exception, which is a bad thing.

Getting back to collections, Kotlin also supports sets, both mutable and immutable. All three types: lists (arrays), maps (dictionaries) and sets (sets), inherit from Kotlin Collection, and in turn from Kotlin Iterable. All three types have a way to count the number of elements (or entries), they can be iterated over, and Collection offers many methods that may or may not apply to each type. For example, you don’t use dropWhile on a map/dictionary.

The Collections reference page lists which functions apply to which types. It’s a bit hodgepodge compared to Swift’s cleaner, hierarchical, and protocol-based system. That said, all the things you would expect to do to an array, set, or dictionary in Swift, you can do to a list, set, or map in Kotlin. Have a browse through that Collections page to get a sense of the functionality. It’s all pretty familiar.

If anything, the various subtypes (LongArray, ByteArray, IntArray, etc) feel like overkill and the available functions feel a tiny bit bloated. But that’s me looking at this stuff with Swift-ized eyes.

If you like this series of posts, let me know. Drop a tweet, email, or comment if you’d like me to keep going.

Swift Style: WWDC Sale

Celebrate style in a half shell during WWDC week!

Pick up a copy of Swift Style with a nice discount. The ebook will be 25% off the normal price during WWDC. Use the coupon code Swift_WWDC_2017 at checkout to apply this dub-dub discount to your purchase of the Swift Style ebook at Pragmatic Programmers. (If you encounter any problems during checkout, contact support@pragprog.com.)

Thank you for reading my blog and supporting me and my books!

Update: the discount is already live. You don’t have to wait until next week:

Four Lessons from Circle Intersection

Yesterday, a fairly simple discussion of circle intersection came up: how do you subtract one circle from another to form a “cut out” Bezier path. This allows you to add an affordance or decoration to a circle, but add some space between the primary figure and the secondary bubble.

Exploring this question provided some interesting lessons that I thought I’d share in a quick post.

Embrace Core Graphics Types

When working with basic geometry, redirect your mathematics to Core Graphics. Bezier paths, points, rects, and other core geometric features use CGFloat, not Double. You minimize your pain by extending CGFloat as needed to address common geometric concerns such as exponentiation or mathematical constants rather than switching back and forth between Swift.Double and CGFloat:

/// Exponentiation operator
infix operator **: HighPrecedence

extension CGFloat {
    /// Returns base ^^ exp
    /// - parameter base: the base value
    /// - parameter exp: the exponentiation value
    public static func **(base: CGFloat, exp: CGFloat) -> CGFloat {
        return CGFloat(pow(Double(base), Double(exp)))
    }
    
    /// Tau
    public static var tau = CGFloat(Double.pi * 2.0)
}

Construct utility types

It helps to think about the kinds of types that will support your geometric challenge. For this example, I built two new types: a line segment (2 end points) and a circle (a center and a radius). Bringing these under the Core Graphics umbrella unified my representations with the tools they need to express their geometry:

/// 2-point representation of line segment
public struct Segment {
    public let (p1, p2): (CGPoint, CGPoint)
    var dx: CGFloat { return p2.x - p1.x }
    var dy: CGFloat { return p2.y - p1.y }
    public var length: CGFloat { 
        return sqrt(dx ** 2 + dy ** 2) 
    }
}

/// Center/Radius circle representation
public struct Circle {
    public let center: CGPoint
    public let radius: CGFloat
}

Being Core Graphic native enables you to leverage constructors using the appropriate types. For example, my circle can construct a path for drawing to a UIKit-compatible context:

/// Returns a Bezier path sweeping between two angles
public func path(from startAngle: CGFloat = 0, to endAngle: CGFloat = CGFloat.tau, 
    clockwise: Bool = true) -> UIBezierPath {
    return UIBezierPath(arcCenter: center, radius: radius,
                        startAngle: startAngle, endAngle: endAngle,
                        clockwise: clockwise)
}

This path method allows me to express each circle as a path, hiding the details of a UIBezierPath constructor. When I want to throw up a visual reference point, I just construct a circle at that point and fill it:

let p1 = Circle(center: segment.p1, radius: 2.5)
p1.path().fill()

Very handy.

Let the math be the math

When you’re working with standard algorithms, it helps to step back from your standard Swift key paths and use the terms of art you’re translating into code. For example, it can be convenient to break down some basic Swift into algorithm-specific terms:

let (x1, y1, r1) = (self.center.x, self.center.y, self.radius)
let (x2, y2, r2) = (other.center.x, other.center.y, other.radius)

It may not be “Swifty”, but doing so leads to easier inspection when comparing your implementation to the how-to reference in a book or paper.

Draw It

Playgrounds are great when it comes to testing drawing algorithms because you can use real data and get immediate results to see whether your assumptions and expectations are properly met.

In this example, the first two circles intersect, allowing the construction of the “chunked out” major circle and a condensed minor circle. The original circles are outlined and the two red points indicate the overlap points.

The second pair does not intersect, so it’s left simply as two outlines.

If you want to play around with this rough implementation, I left the code for this over at github. Feel free to expand or improve upon my approach, as it was very much an off-hand “here’s more or less how you can do this” exercise.

Using memory addresses for hashing

Today, Tim talks about conforming reference types to a hashable program. This enables you to use specific class instances for set elements and dictionary keys. Read on to learn more and don’t forget to follow Tim on Twitter.

For reference types, it often makes sense to consider two variables to be equal when they reference the same address in memory. Say you have a UIView instance visible on screen, for example. You could create a copy of that view with the exact same properties (size, position, background color, etc.) but modifying the copy will obviously have no visible effect.

Testing whether two variables refer to the same instance is easy using the identity operators (=== and !==). However, this does not allow you to put instances of an arbitrary class in a Set, or use them as keys in a Dictionary, since that requires conforming to the Hashable protocol.

Interestingly, classes that inherit from NSObject don’t face this problem: NSObject implements == and hashValue, the two requirements of the Hashable protocol, using isEqual(_:) and hash respectively. The default implementation of isEqual uses pointer equality, and the default value for hash is the instance’s memory address.

In order to use memory addresses for hashing without inheriting from NSObject (which you shouldn’t), you can use the ObjectIdentifier type that is part of the Swift standard library:

final class Foo: Hashable {
    static func == (left: Foo, right: Foo) -> Bool {
        return left === right
    }
    
    var hashValue: Int {
        return ObjectIdentifier(self).hashValue
    }
}

Note that an instance’s memory address can (and will) change across different executions of the program, but that’s fine: the Hashable protocol doesn’t require hash values to be stable across different executions.

Of course, you can put this code in a protocol extension to make it reusable:

protocol PointerHashable: class, Hashable {}

extension PointerHashable {
    static func == (left: Self, right: Self) -> Bool {
        return left === right
    }
    
    var hashValue: Int {
        return ObjectIdentifier(self).hashValue
    }
}

Now, all it takes for a custom class to be usable as set elements and dictionary keys is conformance to PointerHashable. But be careful: the Hashable protocol requires that two instances that are considered equal with == also have the same hash value, so if you are implementing == using custom logic, you will need a custom hashValue implementation as well.

Erica Knows Nothing About Kotlin: Installing and using Kotlin from Xcode

Andy Wilkinson wanted some useful tips for Kotlin in the style of my normal blog. I know nothing about Kotlin other than it’s vaguely Swifty and has a little too much Java in it for my decaf tastes. Nonetheless, I decided to oblige.

Here’s what I discovered.

Install Kotlin

Installation couldn’t be simpler. I used brew: brew install kotlin, which installed a copy to /usr/local/bin/kotlin on my first try. Woo!

Say “Hello World”

You run the Kotlin REPL with kotlinc-jvm, which I did not guess on my first try and had to hunt around doing web searches to discover:

Next, I tried to create an app. Once again I discovered that Kotlin is a little less straightforward than Swift in this regard.

Notice that you have to call kotlinc, the command line compiler, not kotlin. Then you can run the  736709-byte large jar results with (ew) java.

Unfortunately, it’s not as simple as one might hope to create a straightforward script:

However if you rename the file from hello2.kt to hello2.kts, you can run it as a command-line script:

Whee.

Hop into Xcode

Create a new Cross-platform Xcode project: File > New > Project > Cross-platform > External Build System > Next. Enter a name, and edit the build tool to kotlinc. Click Next. Navigate to a save location and click Create.

Choose File > New > macOS > Other > Empty. Click Next. Name the file HelloWorld.kts. (See the kts extension? This allows it to be run as a script.)

Edit your Run scheme (Scheme > Edit Scheme or Command-<). Choose the Info tab, select Other from the Executable pop-up list.

Type a forward slash, then continue to navigate to /usr/local/bin. Select kotlinc, uncheck Debug executable, and then click Close.

Next choose the Arguments tab and edit the arguments passed on launch to include both the -script flag and the source file:

You’re now ready to run:

Do something interesting

Now that you have the basics all ready to play with, create a slightly more interesting testing environment. For example, pull up Project Euler and challenge yourself to a few of their ideas:

That Kotlin “Feeling”

As when I played around with Python, I was surprised at Kotlin’s familiarity.

  • The println commands felt quaint and old fashioned like Swift 1.
  • The cascading dot sequence (which I cut and pasted for the second result, and Xcode didn’t automatically indent) felt as fresh as modern Swift. I also felt pretty confident in my overall Swift-influenced style despite jumping into an entirely new language.
  • Extending Int with the divisibleBy function was a little weird and I deliberately used the = syntax to define my function rather than a more familiar brace and return, just so I could say I tried to be more authentically kotlinny.
  • The two dot range did catch me but it was an easy fix from three dots to two.
  • I quite liked using $-delimited variable names compared to Swift’s \() insertion sequence.

Given that other than a few math functions and hello world, this post contains all my Kotlin code to date, I don’t have much more to add about the language similarities and differences, but let me know if you’d be interested in reading more about “Erica learns Kotlin”. Otherwise, I’ll get back to doing other things during this extremely dead week before WWDC starts.

Tests that don’t crash

Give a big hi to Tim V! He’ll be posting here when a topic inspires him and today, he’s going to talk about how to write tests that fail gracefully.

Most people that have been writing Swift code for a while try to limit their usage of optional force unwraps and try! as much as possible. Test code, on the other hand, is often still littered with unsafe code. It’s true that crashes in tests aren’t nearly as undesirable as in production code, but it’s fairly straight-forward to write tests that fail gracefully when an unexpected nil is encountered, or when an error is thrown unexpectedly.

Consider the following unit tests:

class Tests: XCTestCase {
    func testFoo() {
        let value = try! foo()
        XCTAssertEqual(value, 5)
    }
    
    func testBar() {
        let value = bar()!
        XCTAssertEqual(value, "bar")
    }
}

What a lot of people don’t seem to know is that individual tests can be marked with throws to automatically handle thrown errors:

func testFoo() throws {
    let value = try foo()
    XCTAssertEqual(value, 5)
}

Much better. To write testBar in a safer way, we’ll need to throw an error when the output of bar is nil. We could declare a separate error for each optional value we want to unwrap in one of our tests, but that requires writing a lot of extra code. Instead, we can throw a more general Optional.Error.unexpectedNil each time an unexpected nil value is encountered:

extension Optional {
    enum Error: Swift.Error {
        case unexpectedNil
    }
    
    func unwrap() throws -> Wrapped {
        guard let value = self else { throw Error.unexpectedNil }
        return value
    }
}

Note: Swift 3.0 and below does not support nesting types inside a generic type, so if you’re not yet using Swift 3.1, you’ll have to declare a separate enum OptionalError instead.

Now we can rewrite testBar as follows:

func testBar() throws {
    let value = try bar().unwrap()
    XCTAssertEqual(value, "bar")
}

After these changes, whenever a test would normally crash, it now simply fails. And as a bonus, all tests are guaranteed to be executed, where previously a single crash would prevent the remaining tests from being run.