# Codable, Equatable, Hashable and Comparable — Swift

Source: https://www.skillbyai.com/en/swift/p-codable

> Use standard protocols for JSON coding, equality, hashing and ordering.

## The protocols you use every day

**`Codable`** (shorthand for `Encodable & Decodable`) converts types to and from external formats. With **`JSONDecoder`** and **`JSONEncoder`** you decode API responses into structs and encode them back; customise key names with a nested `CodingKeys` enum or a `keyDecodingStrategy` such as `.convertFromSnakeCase`, dates with `dateDecodingStrategy` (for example `.iso8601`), and handle unusual shapes with a custom `init(from:)`. **`Equatable`** provides `==`, **`Hashable`** allows use as dictionary keys and in sets, and **`Comparable`** enables `<` and sorting; all are synthesised for many structs and enums. **`Identifiable`** (an `id` property) is required by SwiftUI lists. **`CustomStringConvertible`** controls `description` for printing. **`Sendable`** marks types safe to share across concurrency domains (covered later). Combining these standard protocols with value types gives you model objects that are easy to compare, store, serialise and display with almost no boilerplate.

## Decoding a JSON API response

Snake-case keys, ISO 8601 dates and a nested array.

```swift
import Foundation

struct OrderResponse: Codable, Identifiable, Hashable {
    let id: String
    let customerName: String
    let status: Status
    let placedAt: Date
    let items: [Item]

    enum Status: String, Codable { case placed, paid, shipped, cancelled }

    struct Item: Codable, Hashable {
        let sku: String
        let quantity: Int
        let unitPricePaise: Int
    }
}

let json = """
{"id":"o-1001","customer_name":"Asha","status":"paid","placed_at":"2026-10-03T06:45:00Z",
 "items":[{"sku":"PEN-BLUE","quantity":2,"unit_price_paise":4950}]}
""".data(using: .utf8)!

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601

do {
    let order = try decoder.decode(OrderResponse.self, from: json)
    let total = order.items.reduce(0) { $0 + $1.quantity * $1.unitPricePaise }   // 9900 paise
    print(order.customerName, order.status, total)
} catch {
    print("Could not decode order: \(error)")
}
```

## Decoding errors are informative

When decoding fails, print the error: `DecodingError` tells you the exact key path and problem, such as a missing key or a type mismatch. It is the fastest way to debug API changes.

**Quiz:** Which protocol lets a Swift type be converted to and from JSON with JSONEncoder and JSONDecoder?

- [ ] Hashable
- [ ] Identifiable
- [x] Codable
- [ ] Comparable

*Answer:* Codable. Codable combines Encodable and Decodable for serialisation.
