A Glance At Conditional Conformance
Swift 4.1 is available since a few days now and it comes with an interesting feature: Conditional conformance. This is a new tool for achieving Protocol Oriented Programming as well as API designing. This post is a quick take on this brand new technic and will be followed for sure by deep dive posts in a few weeks.
As usual you can find the original post on my personal blog here.
It’s all about extensions
With Swift, one can be a little bit confused with all the different ways of implementing extensions. As the language matures, new extensions possibilities come up and developers have to choose the good one 🤨.
Basically an extension allows to augment the behavior of a type without having to subclass it:
It is useful to make utility functions or to implement an efficient factory pattern.
There is a refinement to basic extension dedicated to generic types:
It would probably not make sense to apply a sum() function to an Array of Bool for instance. This kind of extension allows the developer to bring new features to an existing type but make them safe to use at the same time. It is something very useful when you’re designing an API that is to be used by other developers. They can benefit some code for “free” once and only once they meet the good requirements.
Not only can extensions add behaviors to existing types but also can they amend a type itself to make it conform to a Protocol.
This brings uniformity where there was heterogeneity. It would have been impossible to mix Strings, Ints and Optionals into an Array without having them conformed to the same Protocol.
But, although every element of the Array is a “Resettable”, we still have to parse it (with map) and call “reset()” on each of these to achieve a global operation.
Conditional conformace will help a lot in making this operation seamless for the developer who wants to reset the whole Array.
So far we haven’t spoken about Protocol Oriented Programming. This paradigm comes with the ability to add a default behavior to a Protocol. Types that conform to this protocol will benefit this default behavior as well (or override it). It is a special type of extension and it is not really the point of this blog post. So, let’s not introduce to much noise here and focus on the ability to extend a concrete type.
Conform only if …
Conditional conformance is the brand new feature that comes with Swift 4.1. It is a mix between conditional extension and conformance extension. Being so, it inherits both of their key principles:
- bring new features but make them safe to use at the same time
- bring uniformity where there was heterogeneity
In fact one of the main idea behind that is: if a behavior can be applied to each element of a superset, then we can consider that this behavior can also be applied to the superset itself :
As every element of the Array is Resettable, so is the whole Array. It is exactly what Apple has done with Equatable and Hashable for instance. With Swift 4.1, an Array of Elements that are Equatables, is Equatable itself.
What’s great and very powerful in our example is that we can embed an Array of Resettables inside the root Array, and with only one statement “resettableArray.reset()”, the whole data structure is being reset. It is a very elegant way to deal with recursivity.
As we can see, in terms of API designing we have a great benefit in using “Conditional conformance” over basic “Conformance extension”. The API designer will internalize in its framework the code (here the reset() function) he thinks smart to offer for free to the developers who match the appropriate requirements.
Leverage conditional conformance to ease Design Patterns implementation
There are certain kinds of design patterns that can benefit from the ability that comes with conditional conformance to make a behavior apply to a “container” type. Again, this is mostly seen from an API designer perspective.
Visitor is a pretty simple Design Pattern that allows to externalize the parsing of a data structure. If you want a detailed explanation: Visitor Pattern.
Here, we will implement Persons and Cars, data structures that are “Visitables”. With conditional conformance, Containers of “Visitables” will be “Visitable” as well:
To visit a bunch of Visitables, all you have to do is adding them to a container such as an Array or a Dictionnary and visit this one. From the Developer perspective, only the AnyVisitor has to be implemented.
Be careful with auto-completion
There is a small drawback in using conditional conformance with Xcode. If we get back to our Resettable example, Bool is not Resettable but if we declare an Array<Bool>, Xcode will offer the “reset()” function with the auto-completion.
Of course the compiler will then inform you that Bool is not a Resettable … but still, perhaps Xcode could have been more restrictive ! Not that big a deal 😊 but I had to point that out.
I hope you enjoyed this first take on conditional conformance. New usages will come out for sure in the weeks to come.