Blog

Latest Post

Swift Quiz

Last week, we introduced a fun new format on Twitter, in collaboration with Ahmet Yalcinkaya: Swift Quiz.

In these one day Swift polls, we hope to showcase Swift questions with non-straightforward answers. Some will be practically relevant, and others will lean towards the more obscure end of what you can do in Swift. In any case, we hope they get you thinking for a moment. The next quiz will be up soon! πŸ˜€

Last week, we defined a protocol with a single required method, but two methods in an extension:

protocol Drawing {
    func render()
}

extension Drawing {
    func circle() { print("protocol") }
    func render() { circle() }
}

We then created a type SVG which conforms to the protocol. It also adds a custom implementation of circle:

class SVG: Drawing {
    func circle() { print("class") }
}

The output of calling render on an instance of SVG might be surprising at first:

SVG().render()
// prints "protocol"

Although we’ve defined a circle method on SVG, render doesn’t call it.

There’s a good reason for this: since we didn’t define circle as part of the protocol’s customization points, circle cannot be customized by types that conform to the protocol. In other words, the call to circle from within render is statically dispatched.

Whether this is intended behavior or not depends on what you’re shooting for. Sometimes it makes sense to have a method in a protocol extension that cannot be customized, for example, if it’s a convenience method providing some functionality on top of the protocol’s requirements. However, if we want to allow custom implementations of circle, we need to add it to the protocol:

protocol Drawing {
    func render()
    func circle()
}

Methods declared in the protocol are dynamically dispatched. In this example, the implementation of the circle method that is called will be decided at runtime. We can still have our default implementation in the protocol extension, but we implement a custom version for a specific type conforming to the protocol. This is exactly what the standard library does in many of the collection protocols, and most of the time, it’s a good idea for our own protocols as well.

There is a great deal more to say about this topic, and a short post can only begin to hint in that direction. For an in-depth look at all the features of Swift’s protocols β€” protocol extensions, associated types, type erasers and existentials β€”Β we’d recommend reading our book, Advanced Swift.

To take part in the Swift Quiz, follow us on Twitter, or check out the archive.

Previous Posts

Swift Tip: Generics vs. Any

We are busy updating our book, Advanced Swift β€”Β the new edition will be out by the end of April, as a free upgrade if you previously bought the Ebook.

As part of the update, we are rewriting the chapter on generics from scratch. In this post we preview an excerpt from our most recent draft.

Generics and Any are often used for similar purposes, yet they behave very differently. In languages without generics, you typically use a combination of Any and runtime programming, whereas generics are statically checked at compile time.

When reading code, generics can help to understand what a method or function is doing. As an illustration, consider the type of reduce on arrays:

extension Array {
    func reduce<Result>(_ initial: Result, _ combine: (Result, Element) -> Result) -> Result
}

Assuming that reduce has a sensible implementation, you can already tell a lot from the type signature without looking at the implementation:

  • We know that reduce is generic over Result, which is also the return type.
  • Looking at the input parameters, we can see that the function wants some value of Result, and a way to combine a Result and an Element into a new result.
  • Because the return type is Result, the return value of reduce is either initial, or the return value from calling combine.
  • If the array is empty, we don’t have an Element value, so the only thing that can be returned is initial.
  • If the array is not empty, the type leaves some implementation freedom: the method could return initial without looking at the elements, the method could call combine with one of the elements (e.g. the first or the last element), or with all of the elements.

There are, of course, an infinite number of other possible implementations. For example, the implementation could call combine only for some of the elements. It could use runtime type introspection, mutate some global state, or make a network call. However, none of these would qualify as a sensible implementation. In fact, because reduce is defined in the standard library, and we assume the standard library authors are sensible people, we can be certain that it has a sensible implementation.

Now consider the same method, defined using Any:

extension Array {
    func reduce(Any, (Any, Any) -> Any) -> Any
}

This type has much less information, even if we only consider sensible implementations. By looking at just the type, we can’t really tell the relation between the first parameter and the return value. Likewise, it’s unclear in which order the arguments are passed to the combining function. It’s not even clear that the combining function is used to combine a result and an element.

In our experience, generic types are a great help when reading code. Specifically, when we see a very generic function or method such as reduce or map, we don’t have to guess what it does: the number of possible sensible implementations are limited by the type.

For more theoretical background reading, check out Philip Wadler‘s paper, Theorems for Free.

To start reading Advanced Swift, you can purchase it here.

Swift Tip: From Optionals to Errors

When working with optional values it’s common to check for nil using a guard statement. In cases where the value is not present this results in an early exit. Using an example from our recently open-sourced Swift Talk backend, we often write code that throws an error in the nil case:

guard let gift = g else {
    throw ServerError(privateMessage: "No such gift")
}
// ... rest of the code that uses `gift`

There are many reasons we could run into a nil value; the user might enter an invalid URL, for example, or the database connection might fail. When we encounter nil, we leave the happy path and have to exit early.

Since this pattern repeats itself in a number of places throughout our codebase, we can write an extension on Optional that abstracts this pattern away:

extension Optional {
    func or(_ err: Error) throws -> Wrapped {
        guard let value = self else {
            throw err
        }
        return value
    }
}

Using this extension, we can write our initial example like this:

let gift = try g.or(ServerError(privateMessage: "No such gift"))

We could also choose to use a custom operator, which might stand out more when reading the code:

infix operator ?!: NilCoalescingPrecedence
public func ?!<A>(lhs: A?, rhs: Error) throws -> A {
    guard let value = lhs else {
        throw rhs
    }
    return value
}

The NilCoalescingPrecedence group specifies that our new operator has the same precedence as ??.

Using this operator, the example now looks like this:

let gift = try g ?! ServerError(privateMessage: "No such gift")

We find that small abstractions of common patterns can remove some of the noise from our code, making it more readable overall.

For those instances where you care less about the specific error message, you could try creating a postfix operator, similar to the one used for force-unwrapping.

To learn more about our Swift Talk backend, watch the first episode of our latest series, or check out the full source code on GitHub.

Our book, Advanced Swift, discusses Optionals and error handling in more depth. We’re preparing an update for Swift 5, free for all Ebook readers. πŸ‘

Updating Advanced Swift

2019 02 19 ole swift mind map

β€” Ole Begemann’s Swift notes mind map, July 2018.

As some of you may have noticed, we recently started working on a fourth edition of our book, Advanced Swift. Many of you have been asking, and we’re glad to make it official.

Swift 5.0 brings some important improvements, and there are many small things we’d like to update. We’ll be adding some new chapters too, covering bigger themes. We also have a little experiment planned… more news on that soon!

For those new to Advanced Swift, the book ranges from low-level programming, such as string internals and wrapping a C library, to high-level abstractions, such as programming with generics and protocols. If you’ve read Apple’s The Swift Programming Language and want to dig deeper, this book is for you.

The update will be free for everyone who has already purchased the Ebook.

Enjoy! 😊

Ole, Florian and Chris

Open-Sourcing The Swift Talk Backend

Today, we are open-sourcing the Swift Talk backend, written in Swift.

The Ruby Beginnings

Before launching Swift Talk, our weekly video series, we spent much of our time trying to figure out the best format for an episode. We experimented with many pilot recordings, discarding every one of them before settling on our current conversational style. To help us focus on the content we decided to outsource our backend development, working with an external contractor to build the site in Rails. This was great for launching, but very quickly our limited Rails experience, and the major differences between Swift and Ruby, made changes to the backend very time-consuming.

When refactoring in Swift, we rely heavily on the strong, static type system. For example, this allows us to change a method signature, then rely on the compiler to guide us through all call sites and any tests that are in place. In Ruby or Rails, you can’t rely on a static type system when making changes. Instead, you rely exclusively on an extensive test suite, and your knowledge of the code base and the frameworks to guide your refactoring.

Ruby on Rails also relies heavily on meta-programming, which makes it possible to achieve a lot with very little code. Likewise, if you’re not intimately familiar with the framework it can be quite hard to trace through your application and understand what is happening.

Finally, even for such a simple project, our Ruby code base had a lot of dependencies β€”Β 75 to be exact (some were transitive, but most were direct dependencies). Over time these needed to be updated, and we had to make sure that all the dependencies and our code kept working together as expected.

Rewriting the Backend in Swift

After finishing our latest book, App Architecture, we decided to spend our newly quiet days tackling the backend rewrite. A rewrite would have no direct business value, but even so, the project would be fun and interesting, and this can be reason enough. We wanted to prove to ourselves that Swift was feasible as a backend language, that we could rely on the type system for refactoring, and that we could make do with minimal dependencies.

Over the last few months, all of these have turned out to be true.

Preparing the code for public release, we wanted to clean it up and make sure that it was readable. We extracted non-app-specific parts into frameworks, conducted some large-scale renaming, and refactored many things. The compiler and type system were a huge help.

We now only have six direct dependencies: the web server library SwiftNIO, a Postgres client, a Markdown library, an XML parsing library, an encryption library and SourceKitten for source code highlighting. Most notably, we’re not using a web framework, but are building directly on top of SwiftNIO, so that we can structure the code in our own way.

Good News: it Works!

So far, we love working on this code base. With so few dependencies we own almost all of our code, and can design and extend it in ways that works for us. We are no longer stuck with a Rails backend that we found hard to change, and we can add features quickly, such as the new team member signup pages.

For us, the biggest downside is that Swift on Linux isn’t battle-tested. We ran into a few bugs (most notably around URLSession/URLRequest behavior), but they were easily solved or worked around. Battle-testing has to start somewhere, and we expect this will only improve with time.

We aren’t the first to build a project like this in Swift. Point-Free was written in Swift at launch, and it continues to be an inspiration β€” it’s no coincidence that our Dockerfile is so similar to theirs.

We’re planning to add more features to Swift Talk, and we hope that open-sourcing our code base will inspire other people to write their backend in Swift as well.

The full source code is on GitHub.

If you’d like to learn more, our latest public episode starts a new series exploring what it’s like to work with the backend. The rewrite also informs many of the episodes in our Server-Side Swift collection.

To follow the series, you can subscribe.

Enjoy! 😊