With Swift 5 officially released 🎉, we're busy updating Advanced Swift for an expanded fourth edition. This week, we'd like to share a brief overview of collection protocols, which we'll be discussing in more depth in the book.
In Swift, there are a number of collection protocols, each with their own features:
Sequence provides iteration. It allows you to generate an iterator, but there are no guarantees about whether the sequence is single-pass (e.g. reading from standard input) or multi-pass (iterating over an array).
Sequence. It guarantees that the sequence is multi-pass, and allows you to look up elements by their index. It also adds a
SubSequence type, which is a collection itself.
MutableCollection adds the ability to mutate an element through a subscript in constant time. It does not allow you to add or remove elements. Notably,
String does not conform because characters in a string are variable-width (which means replacing a character could take linear time).
String.UnicodeScalarView does conform.
RangeReplaceableCollection adds the ability to replace a contiguous range of elements in the collection. By extension, this also adds methods like
remove, and so on. Many mutable collections are range replaceable as well, but there are exceptions. Most notably,
Dictionary don't conform, but types like
Array do conform.
BidirectionalCollection adds the ability to iterate backwards through a collection. For example, a
Dictionary doesn't allow reverse iteration, and doesn't conform, but a
KeyValuePairs (previously called
DictionaryLiteral) does. Backwards iteration is critical for some algorithms.
BidirectionalCollection and adds the ability to compute with indices more efficiently: it requires that measuring the distance between indices and moving indices by a certain distance takes constant time. For example, an
Array is a random access collection, but a
String is not: computing the distance between two string indices takes linear time.
LazySequenceProtocol is similar to a sequence, but iteration becomes lazy. This is mostly useful for writing algorithms in a functional style: you can take an infinite sequence, filter it, and then take the first element.
LazyCollectionProtocol is the same as
LazySequenceProtocol, but for collections.
When you write your own algorithms, it can be very useful to have this protocol hierarchy in mind: if you can write an algorithm on one of the protocols towards the top of the hierarchy, more types will get the same functionality.
The new edition of Advanced Swift will be released by the end of April. If you've already bought the Ebook, this will be a free upgrade. 👍
Our current Swift Talk mini-series looks at String Interpolation in Swift 5, which we use in our Swift Talk backend to automatically insert placeholders in SQL queries. The first episode is public.
Swift Talk subscribers can explore many of these topics in our collection, Swift, The Language. To support our work, and access all episodes, become a subscriber.