Swift Standard Library: Generators, Sequences and Collections

A large part of the Swift Standard Library is concerned with Generators, Sequences and Collections and functions that operate on them, so it’s pretty important to have a good understanding of them.

Generators

A Generator is anything that conforms to the GeneratorType protocol.
It’s fairly simple.

So a generator is simply something that can give you the next element of some sequence of elements. If there is no next element it returns nil.

With this information, we could create a generator, say, of powers of two.

This code conforms to the protocol and is a valid GeneratorType but it is not very easy to use. It will produce an infinite number of elements, without external logic.

For example, to print the first 10 powers we would need to do the following:

We can make it a little easier to use by adding an initializer to set a limit
on how many values we will print.

This version is much easier to use.

OK, so now that we have a generator what can we do with it? Well the answer to
that is… not very much. Very few of the Standard Library Routines take a GeneratorType directly; they require a sequence.

Sequences

A sequence is anything that conforms to the SequenceType protocol. It’s defined as:

Essentially a sequence is a generator factory; something that knows how to make
generators for a sequence.

A first attempt at a power of 2 sequence might look something like this.

As a first attempt this is not bad. This code works and have new capabilities, for example, we can now write:

But there is a problem. It’s easier to see if we move the generator inside the
sequence class.

Hopefully now the problem is plain to see. There is a lot of code repetition here. The two inits are almost identical, the endPower variable is repeated. Surely we can do better? And, of course, we can.

It’s a little subtle what’s going on here, so let’s dig a little deeper. All
the generator logic has been moved into a closure nextClosure.
The closure captures the endPower from the enclosing class and the current
power from the generate function. Finally, the GeneratorOf<T> class is a
Standard Library Class that conforms to GeneratorType and
knows how to use the closure to implement the next method.

Using trailing closure and type inference we can also write this as:

Collections

A collection a sequence that conforms to the CollectionType protocol.
The CollectionType protocol is defined as follows.

So a CollectionType is a SequenceType that can be accessed via a subscript and defines a startIndex and endIndex.

We can upgrade our PowersOfTwoSequence to a Collection with a few small code changes.

While many standard library functions can operate on sequences, some,
for example reverse require an object conforming to CollectionType.

Conclusion

In this post I have examined the three main protocols that Swift uses to underpin many of its functions that operate on sequences and collections and presented example code for each one.

A playground containing all the code from this post is available in the GitHub repository SwiftStandardLibraryPlaygrounds


About idz

A professional software engineer dabbling in iOS app development.
This entry was posted in Swift, Swift Standard Library, Tutorial and tagged , , , , . Bookmark the permalink.

Leave a Reply