Which of these conditional conformances are more useful?
Earlier today I posted a tweet with a question: which of these two conditional conformances enables more functionality?
// Option 1
extension Stack: Codable where Element: Codable {}
// Option 2
extension Stack: Encodable where Element: Encodable {}
extension Stack: Decodable where Element: Decodable {}
The question was deliberately worded a little vaguely, partly because I was right up against Twitter’s character limit, but partly also because I was curious if people could make a case for both sides.
I offered up four poll options:
The correct answer is option 2, although after 370 votes it only managed third place. If you’re not sure why, let’s break it down…
SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until September 29th.
Sponsor Hacking with Swift and reach the world's largest Swift community!
What we’re seeing here is a Swift feature called conditional conformance: adding a conformance only for a subset of a type when specific criteria are matched.
Conditional conformance is used frequently in Swift. For example, it’s how we can compare optionals for equality if they wrap things that are equatable:
extension Optional: Equatable where Wrapped: Equatable { ... }
And here’s how we can easily sort sequences when they contain objects that are comparable:
extension Sequence where Element: Comparable { ... }
In my tweet I posed two options. The first makes a Stack
collection conform to Codable
if all its elements conform to Codable
, like this:
extension Stack: Codable where Element: Codable {}
The second makes the same Stack
collection conform to Decodable
if its elements do, and Encodable
if its elements do:
extension Stack: Encodable where Element: Encodable {}
extension Stack: Decodable where Element: Decodable {}
If you aren’t familiar with how Codable
is implemented, here’s a line of code taken straight from Swift itself:
public typealias Codable = Encodable & Decodable
As you can see, the Codable
protocol really isn’t a protocol at all – it’s just a typealias for the composition of Encodable
and Decodable
. So, that means the first answer to my question actually looks like this:
extension Stack: Encodable & Decodable where Element: Encodable & Decodable {}
Now that we’ve expanded what Codable
means it might look like my two options do the same thing, but they don’t.
When applying conditional conformance, Swift makes sure all your rules are matched fully. In the case of Encodable & Decodable
it means that Stack
will be made to conform to those protocols only if its elements conform to both. So, if you make a type that conforms only to Decodable
because you want to create objects from JSON data but never want to do the reverse, arrays of that type won’t qualify for the conditional conformance.
On the other hand, if you create separate conditional conformances for Encodable
and Decodable
then:
Encodable
qualify.Decodable
qualify.Encodable
and Decodable
qualify.If we had used Codable
instead only the third item would apply.
So, to answer my original question: creating two separate conditional conformances enables the most functionality, because it lets more of our types gain some form of codability.
When I posted the question I wanted to leave open the possibility of someone making the case for option 1 – that they considered encodability and decodability fundamentally entwined.
While I can theoretically imagine this, I’m struggling to see a use for this kind of restriction in practice. Remember, Codable
isn’t actually a protocol, so we can’t write protocol extensions for it.
If you can think of a reason why option 1 is preferable I’d love to hear it – send me a message on Twitter!
SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until September 29th.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.