NEW: Master Swift design patterns with my latest book! >>

Apple's new Utility library will power up command-line apps

Paul Hudson    December 1st 2017    @twostraws

Apple has unveiled a new collection of open-source utility code for Swift developers, grown out of its Swift Package Manager project. The collection contains some interesting new data types (OrderedSet – hurray!), some tools to make command line programs easier to write, and some helpers for common tasks like temporary files and SHA hashing.

Apple describes the code with a big warning that bears repeating before we continue: “This product consists of unsupported, unstable API. These APIs are implementation details of the package manager. Depend on it at your own risk” Still, who could resist having a quick play? Let’s see what we have…

Using the library

Start by creating a new Swift project:

  1. Launch Terminal.
  2. Run cd Desktop to change to your Desktop directory, if you aren’t there already.
  3. Run mkdir UtilityTest and cd UtilityTest to make a directory and change into it.
  4. Run swift package init --type=executable to generate a new command-line project.

Now modify open Package.swift in the UtilityTest directory and modify it to this:

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "UtilityTest",
    dependencies: [
        .package(url: "", from: "0.1.0"),
    targets: [
            name: "UtilityTest",
            dependencies: ["Utility"]),

That brings in the Swift Package Manager project, which is where Apple’s new utility code lives for the time being.

Finally, run swift package generate-xcodeproj to download our lone dependency and generate an Xcode project. When that finishes, open it in Xcode, then open main.swift inside the Sources > UtilityTest folder, and give it these three imports:

import Foundation
import Basic
import Utility

That’s the setup complete, so let’s try it out!

Ordered sets

First up, we have a new OrderedSet type that gives all the performance of sets without their annoying habit of forgetting the order you add things. The code for this might surprise you with its simplicity: it’s a data type that combines an array and a set so that one can be used for storing order while the other is used for look ups.

Here’s how a regular set looks:

let set = Set(["Anna", "Olaf", "Elsa", "Kristoff", "Anna"])

When printed out, that contains ["Elsa", "Kristoff", "Anna", "Olaf"] – all the order has been lost. Moving over to an ordered set is now trivial:

let set = OrderedSet(["Anna", "Olaf", "Elsa", "Kristoff", "Anna"])

Sorted arrays

Moving on, there’s a new SortedArray type that ensures new data is always insert into the correct alphabetical position. For example:

var array = SortedArray<String>()

When that code finishes, the array will contain Anna, Hans, Kristoff, Sven. (Some trivia for you: the names Hans, Kristoff, Anna, and Sven were chosen to honor the Danish author Hans Christian Andersen, who wrote the book Frozen was based on – the Snow Queen.)

Obviously SortedArray might cause a serious performance slowdown compared to using a regular array and sorting only once, so use it wisely.

A real Result type

Next up, we’ve got a dedicated Result type, which is something a vocal minority of developers have been calling for since Swift 1.0. This lets you return the result of a function if everything went to plan, or an error type if everything went wrong – it’s a bit like returning an optional, except rather than nil being sent back you get an error explaining what went wrong.

To demonstrate this, we could write some code to check how strong a passcode was. First, we need an error we can send back, and I’ll give it one case – the code was obvious:

enum EncryptionError: Error {
    case obvious

Next we’re going to write a trivial method to check a passcode. If the code is “12345” we’ll report back that the function failed because the code was too obvious, but otherwise we’ll rate the passcode 0 to 10 based on how many characters it has. It should go without saying that this is deliberately simplified – please don’t use this for actual passcode checking!

Here’s the function:

func checkPasscode(str: String) -> Result<Int, EncryptionError> {
    if str == "12345" {
        return .failure(.obvious)

    return .success(min(str.count, 10))

Notice how it returns Result<Int, EncryptionError>, which means when things fail we need to send back something from our EncryptionError enum, but when they work we’ll send back the (woefully inadequate) score of the passcode.

We can now call that function, and put the result straight into a switch block to figure out what happened:

let input = "fr0st1es"

switch checkPasscode(str: input) {
case .success(let strength):
    print("Your password strength is \(strength)/10")
case .failure(.obvious):
    print("I've got the same combination on my luggage.")

Localized array joins

It’s very small, but Apple added a useful little array method called localizedJoin(). It joins arrays using a special token for the final item, giving results like “1, 2, and 3” rather than just “1, 2, 3”. It comes in two flavors:

let names = ["Peter", "Jane", "Mummy too"]
print(names.localizedJoin(type: .conjunction))
print(names.localizedJoin(type: .disjunction))

The first print() sends back “Peter, Jane, and Mummy too”, and the second sends back “Peter, Jane, or Mummy too”.

Before you use it, be warned: this method only supports English, and always uses Oxford commas. That is, you get a comma before the “and”, which may or may not be to your liking.

Launching processes

Writing command line apps has its own set of complexities, particularly if you want them to be cross-platform across macOS and Linux. Fortunately, Apple’s new utility code takes away a lot of the pain of dealing with POSIX compliance, wrapping it all up in some great little helpers.

For example, a common task is to run another process, wait for its result, then take some action based on that result. Thanks to the new Process type, this is surprisingly easy – here’s some code to list your Applications directory:

do {
    let process = Process(arguments: ["ls", "-l", "/Applications"])
    try process.launch()
    let result = try process.waitUntilExit()
    let output = try result.utf8Output()
} catch {
    print("Error while reading the Applications directory")

You can also read errors (stderr), exit status, and more.

Working with temporary files

Another brilliantly simple helper is TemporaryFile: it’s a class that instantiates a new file you can write to freely, but as soon as your file object goes out of scope – e.g. your method returns or your loop ends – it gets deleted. (Note: it’s down to the operating system when the file actually gets deleted.)

In its most simple form here’s how TemporaryFile works:

let file = try TemporaryFile()
let data = Data("Hello, world!".utf8)

You can also add your own prefix or suffix to the filename if you want, like this:

let file = try TemporaryFile(prefix: "hws")

And if you want to know where the file is being stored, you can read its path like this:


Managing versions

Another great little helper is Version, which is perfect for handling semver checks in your code. You can create a new Version instance from major, minor, and patch numbers, then compare instances, like this:

let currentVersion = Version(1, 5, 0)
let newestVersion = Version(2, 0, 1)

if currentVersion < newestVersion {
    print("Upgrade is available!")

You can also create versions from strings in the format “X.Y.Z-prereleasedata”, but this returns an optional:

if let version = Version(string: "2.0.0-alpha4") {
    print("You're running v\(version.major)")

Calculating SHA hashes

Finally, there’s a new SHA256 class for computing the SHA-2 hash of strings. While I wish it were a simple String extension, that’s just because I’m lazy – here’s how to use it:

let sha = SHA256("Time doesn't exist; clocks exist.")

Parsing arguments

There are a few common things any command-line app wants to do, and Apple’s utilities have gone a long way to making them easier.

First, there’s a new ArgumentParser class that’s responsible for reading arguments from the command-line and making them available to your program. You start by creating an instance of the class, like this:

let parser = ArgumentParser(commandName: "swearcheck", usage: "filename [--input naughty_words.txt]", overview: "Swearcheck checks a file of code for swearing, because let's face it: you were angry coding last night.")

That provides ArgumentParser with some basic information to show if the user runs the program using -h or --help. You can then go ahead and add positional or optional arguments, like this:

let input = parser.add(option: "--input", shortName: "-i", kind: String.self, usage: "A filename containing naughty words in your language", completion: .filename)
let filename = parser.add(positional: "filename", kind: String.self)

That first one will look for both “--input filename.txt” and “-i filename.txt”, whereas the second one will look just for a loose value to be read.

Once you’ve configured your parser you can go ahead and use it. Most of the time you’ll want to use the input from the command line (dropping the first item, because that contains the program name), like this:

let args = Array(CommandLine.arguments.dropFirst())
let result = try parser.parse(args)

Finally, you can read individual arguments by calling get() with the argument you created, like this:

if let wordsFilename = result.get(input) {
    print("Using \(wordsFilename) for the list of naughty words to check for.")
} else {
    print("Using 'JavaScript' in lieu of a list of naughty words.")

ArgumentParser will throw errors if values were missing or incorrect, so you should really wrap the whole thing in a do/catch block, like this:

do {
    let parser = ArgumentParser(commandName: "swearcheck", usage: "filename [--input naughty_words.txt]", overview: "Swearcheck checks a file of code for swearing, because let's face it: you were angry coding last night.")
    let input = parser.add(option: "--input", shortName: "-i", kind: String.self, usage: "A filename containing naughty words in your language", completion: .filename)
    let filename = parser.add(positional: "filename", kind: String.self)

    let args = Array(CommandLine.arguments.dropFirst())
    let result = try parser.parse(args)

    guard let codeFile = result.get(filename) else {
        throw ArgumentParserError.expectedArguments(parser, ["filename"])

    print("Scanning \(codeFile) for sweary code…")

    if let wordsFilename = result.get(input) {
        print("Using \(wordsFilename) for the list of naughty words to check for.")
    } else {
        print("Using 'JavaScript' in lieu of a list of naughty words.")
} catch ArgumentParserError.expectedValue(let value) {
    print("Missing value for argument \(value).")
} catch ArgumentParserError.expectedArguments(let parser, let stringArray) {
    print("Missing arguments: \(stringArray.joined()).")
} catch {

Enhancing your terminal output

Moving on, the TerminalController class gives you more control over the terminal window, as you might have guessed from its name. This includes things like printing text in color, clearing the current line, and measuring the terminal width in characters.

To demonstrate this, we could write a simple text string user super cool colors, and by “super cool” I really mean “the kind of thing you wrote when you were 14”:

let colors: [TerminalController.Color] = [.red, .green, .yellow, .cyan, .white]

if let stdout = stdoutStream as? LocalFileOutputByteStream {
    let tc = TerminalController(stream: stdout)

    for (index, letter) in "Hello, world!".enumerated() {
        tc?.write(String(letter), inColor: colors[index % colors.count], bold: true)


Displaying progress

Last but not least, built on top of TerminalController is another helpful class called ProgressBar – again, as you’d expect from its name this prints a progress bar into the terminal, neatly moving across the screen as you adjust its completion percentage. Helpfully, the progress bar will automatically size itself to the width of the terminal window, so you just need to worry about telling it how much has completed.

Here’s an example to get you started – this counts from 1 to 100 over 100 seconds, updating the progress bar to reflect how much of a particular download has completed:

let progressBar = createProgressBar(forStream: stdoutStream, header: "Fetching dependencies")

for i in 1...100 {
    progressBar.update(percent: i, text: "Vapor")


Will it end up being separate?

This has been a pretty long article, and we’ve covered probably only about 25% of what the new library offers. Hopefully you can see there’s a heck of a lot here, and this was just me covering the highlights.

At this point, the Swift package manager doesn’t support multi-package repositories, which is why all this code is in one place even though it doesn’t really all fit together. That being said, it feels very much like some of these things could easily go on to Swift Evolution if Apple were so inclined – OrderedSet might be a quick win, whereas Result might prove a little more controversial!

Before you starting adding this code to big projects, remember Apple’s warning: it's unstable and unsupported, at least for now. While it’s interesting to see their direction of travel, and always great to see new open source code, keep in mind that it can change dramatically at any point in the future!


About the author

Paul Hudson is the creator of Hacking with Swift, the most comprehensive series of Swift books in the world. He's also the editor of Swift Developer News, the maintainer of the Swift Knowledge Base, and Mario Kart world champion. OK, so that last part isn't true. If you're curious you can learn more here.

Click here to visit the Hacking with Swift store >>