The other day I had an interesting small problem to solve. How to create a custom collection type which could have other kinds of collections as a base collection. The use-case for the collection is being a middle layer for data sources of different types. Another important requirement was that we want to avoid any expensive array allocations. Otherwise, we could just initialize these data source with Swift Array and call it a day. Moreover, base collections could even change during runtime, therefore the custom collection can’t reference any concrete types of the base collection using generics.
The high-level definition of the collection look like this: struct WrappedCollection<Element>: RandomAccessCollection.
After researching this and digging through Swift collection documentation without any great ideas, I suddenly realized that the solution was simpler than expected. If we can limit WrappedCollection’s Index type to Int (one of the required associated types), then the collection’s implementation becomes really short, since then we can benefit from RandomAccessCollection‘s default implementations for required functions and properties. This means, we just need to implement startIndex, endIndex and subscript for accessing an element at index. If it is just three properties and methods to implement, and we want to avoid exposing the type of the base collection, then we can use closures. Simple as that.
Since the base collection is captured using closures, the base collection’s type can be anything as long as it follows some basic limits where the Index associated type is Int and the generic Element types match. In the end, we can create a property of the new type, which can change the base collection type in runtime. Here is an example:
Just to reiterate that this makes sense only when it is too expensive to initialize Swift Array with elements of other collection types. Most of the time it is OK, but if not, then we can use the approach presented in this post.
If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.