Hummingbirds and Swifts
Hummingbirds and Swifts (source: Pixabay)

Last week, Apple released their new programming language, Swift, as an open source project. Apple promised at WWDC 2015 that the entire language would be released under an OSI-approved license. What we got was far more than that: in addition to the source code to the compiler, we received the beginnings of a native-Swift implementation of the Foundation library, which serves as the standard library for all OS X and iOS applications. Everything was released under the Apache 2.0 license.

By releasing this source code, Apple has unlocked a critical piece of functionality that has previously limited Swift to Apple's walled-garden platforms. As fantastic as these platforms are to develop for, they're only a fraction of the larger universe; by making Swift available to the greater community, this tremendously interesting language can be applied to a much broader scope.

Since there's so much to cover, we'll split it up into three posts. In this and forthcoming posts, we'll talk about the following:

  1. Why Swift is interesting, and what you can do with Swift
  2. The practicalities of the Swift open source release
  3. What Swift might be useful for in the future

Let's start with the interesting bits.

Why Swift is Interesting

Let's get it out of the way, up front: if you're interested in developing for Apple's platforms, or if you're already developing for Apple's platforms, but are using Objective-C, then you need to learn Swift, as soon as you can. If you're not developing for Apple's platforms, which include OS X, iOS, tvOS, watchOS, and who-knows-what in the future, then right now, the practical applications of Swift are limited to only a few things, such as proof-of-concept implementations in non-Apple platforms. However, this is now changing, and we'll no doubt see an expansion of the Swift-affected world.

So, why is Swift interesting? Swift is an extremely modern language, with a whole bunch of interesting, clever, and well-considered features and design elements. Swift has a very elegant syntax, strong safety, and is extremely fast, owing to its heritage derived from the LLVM compiler project. Swift has a number of especially interesting features for developers: optionals, a very cool error-handling system, and Swift's adherence to protocol-oriented architecture.

In Swift, values are not allowed to be null. If you declare a value as Int, it's required to have an integer value; if you declare a value as a String, it's never allowed to be nil.

    var myString : String
    myString = nil // error!

It's actually a compiler error if you attempt to set a variable to nil. Variables in Swift are only allowed to be nil, if they'reĀ optional variables. An optional variable is declared with a question mark after its type, like so:

    var myOptionalString : String?
    myOptionalString = nil // allowed

By strictly controlling when and how a variable is allowed to be nil, a whole host of errors can be avoided. Because a variable's nullability can be determined at compile time, a huge number of null checks can be avoided.

In addition to optionals, Swift provides an interesting error-handling system. This system, derived from the older NSError system used in Objective-C APIs, separates the idea of exceptions into two separate concepts: errors that are the fault of the programmer, and errors that result from either user input or the environment. This separation is important, because it's not the user's fault if you failed to check the bounds of an array before attempting to access a value, but the user should be notified if the app couldn't save a file because the disk is full.

As a result, Swift divides problems into exceptions and errors. Exceptions are thrown by the system, and always result in your program exiting with an error, while errors are triggered by problems that the user can at least attempt to deal with.

In addition to this useful separation of problem types, Swift's syntax requires you to be especially careful about functions that can possibly cause problems. For example, consider the following (somewhat contrived) snippet of Java:

    try {
            openFile();
            String data = getData();
            writeToFile(data);
    } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
    }

In this example, it's not possible to know which of the three lines in the try sections could possibly result in an exception being thrown. Let's look at the equivalent in Swift:

    do {
            try openFile()
            let data = getData()
            try writeToFile(data)
    } catch let error {
            println("Error: \(error)")
    }

In Swift, any function that can throw an error is required to be wrapped in a do block, or else their calling method must be marked as throws, just as methods in Java must either bet wrapped in a try block or have their calling function list the possible exceptions that they can re-throw. However, Swift differs in an interesting respect: each individual line that can throw an error must be prefixed with try. This allows anyone reading the code to quickly understand which methods might fail; in this example, openFile and writeToFile are the possible lines that can cause a problem. This instant boost in comprehensibility allows the programmer to not only grasp the intention and flow of the code they're reading, but also develop a wider understanding of the code that's being used.

Finally, Swift has a strong adherence to protocol-oriented development. In Swift, along with many languages, there's this idea of a a data type that contains a list of possible methods that a method can implement. Java and C# refer to this as an interface, while C++ refers to it as an abstract base class. In Swift, it's called a protocol. You can define, for example, a protocol that defines methods related to processing some data:

    protocol IntegerProcessing {
             func processNumber(number : Int) -> Int
    }

Any class can then choose to conform to the protocol, like so:

    class MyNumberProcessor : IntegerProcessing {
            func processNumber(number : Int) -> Int {
                    return number * 2
            }
    }

So far, this is pretty standard stuff for seasoned object-oriented programmers. However, the real strength and flexibility comes from the fact that the majority of the Swift standard library, and indeed the Swift langauge itself, is largely implemented through protocols.

Let's consider a very simple example, involving the ability to compare two values. In all popular programming languages, it's possible to compare two integers to each other, using the == operator:

    2 == 2 // true

In slightly fewer popular languages, including Swift, this ability to compare is extended to Strings:

    "foo" == "bar" // false

This ability to compare comes from the Equatable protocol, which requires that any class that conforms to it ("implements", in Java/C# parlance) implement a version of the == operator, which allows two objects of the same type to be compared against each other.

Almost every single aspect of the Swift language comes from this philosophy of protocols defining the behavior of objects, rather than their inheritance trees. It's a tremendously exciting approach to development, and one that we'd love to see applied elsewhere.

These features, and more, are responsible for Swift achieving its designers' goals of being "fast, modern, safe, and interactive". Swift is extremely good at mobile and desktop application development: you can build your software quickly, using an interactive REPL, and get good performance from the resulting code.

In the next post, we'll discuss the practicalities of the Swift open source release, and what it means for non-Apple developers. Spoilers: it's pretty great.

Article image: Hummingbirds and Swifts (source: Pixabay).