NEW: Join my free 100 Days of SwiftUI challenge today! >>

Conforming to Codable vs Encodable and Decodable

Which of these conditional conformances are more useful?

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!

SPONSORED Instabug helps you identify and resolve severe crashes quickly. You can retrace in-app events and know exactly which line of code caused the crash along with environment details, network logs, repro steps, and the session profiler. Ask more questions or keep users up-to-date with in-app replies straight from your dashboard. Instabug takes data privacy seriously, so no one sees your data but you! See more detailed features comparison and try Instabug's crash reporting SDK for free.

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) 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 a speaker at Swift events around the world. If you're curious you can learn more here.

Was this page useful? Let us know!