When looking at how to design and structure our own code, it's often best to start with what exists in the language and platform that we are working in. So, when it's time to design a new type, such as a SortedArray
or Set
, how would we implement this in Swift?
I'm guessing that your first thought is to inherit the Array
class and override the insertion methods and indexing setter (unless you're already familiar with Swift…). However, that will not work because the Array
class in Swift is not a class at all, it is a struct. There has been much discussion about this on the developer forums and I also wrote about some of my concerns with them already, but most of that was with the broken semantics of arrays with the let construct; I did not see much in the context of the problems with extensibility.
There is a good argument that this is bad example as the APIs are slightly different between an
Array
and aSet
class, but the metapoint still stands.
: .info
If we look at the Swift documentation, this is what we learn about structs, or rather, the benefits of classes over structs:
Classes have additional capabilities that structures do not:
- Inheritance enables one class to inherit the characteristics of another.
- Type casting enables you to check and interpret the type of a class instance at runtime.
- Deinitializers enable an instance of a class to free up any resources it has assigned.
- Reference counting allows more than one reference to a class instance.
I've bolded the part that is going to limit us in our design choices. We really only have two options available to us now:
- Composition 2. A new implementation
Neither of these approaches is ideal because they require significantly more code than the inheritance choice we should have had.
This goes back to my original thoughts on Swift and one of the foundational aspects of Objective-C: extensibility. When I referenced that, I was not talking about the extensibility of the ObjC language, but rather, the extensibility of every type in the system.
Swift, at it's heart, seems to be going against that at fundamental level. The two biggest pieces of evidence for this are the the following:
- Every type we have seen thus far in the Swift Standard Library has been declared as a struct. Interestingly enough, many are also backed by internal class types. 2. The introduction of the
@final
construct to specifically prevent inheritance and extending the functionality of class types
So what is the take-away when foundational types of the language that are classic examples of types that should be classes are implemented as structs? To me, it seems the API designers for Swift are already compensating for weaknesses in the language's runtime and are trading supposed run-time performance over platform extensibility and that we, as developers of frameworks, should be doing the same.