FREE: Read a new Swift article every day – click here! >>

Conforming to Codable vs Encodable and Decodable

Paul Hudson       @twostraws

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:

  1. Option 1
  2. Option 2
  3. Both are the same
  4. Just show me the results

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…

Conditional conformances in action

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:

  1. Types that conform just to Encodable qualify.
  2. Types that conform just to Decodable qualify.
  3. Types that conform both to 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.

But what about…

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!

 

MASTER SWIFT NOW
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

About the author

Paul Hudson is the creator of Hacking with Swift, the most comprehensive series of Swift books in the world. He's also the editor of Swift Developer News, the maintainer of the Swift Knowledge Base, and Mario Kart world champion. OK, so that last part isn't true. If you're curious you can learn more here.

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>