Requiring Codable conformance

I need to conform a custom type T to Codable and one of the stored properties of T is a heterogeneous array like so:

// There are currently 5-6 conforming types and this number is expected
// to change slowly.
protocol FooProtocol { ... }

struct T {
  var foos: [FooProtocol]

Is there a commonly accepted way / idiom(s) for dealing with this situation? I've considered the following:

  1. inheriting FooProtocol from Codable, this will require all types conforming to FooProtocol to also implement Codable conformance,
  2. in this particular case, FooProtocol and its conforming types can be replaced with an enum with associated values, which depending on the associated values can be automatically conforming to Codable,
  3. anything else?

In my particular case, I think 2. above is the best solution but this may not always be possible. In that case I am left with 1. or are there any alternatives that I should know of?


I'd go with an enum, in this case it'll work out of the box.

Could you give an example?

I don't think #1 is sufficient. Say two types implementing the protocol have properties with the same names, but use those properties for different things, or expose different methods. From the serialized properties alone it isn't possible to tell which type it originally was, even with the restriction of some FooProtocol & Codable.

1 Like

I had a situation like this recently. I was able to accomplish this cleanly with an enum and then I had codable structures with arrays of these entities. Also, by making all the records (which are codable structs) use a protocol for the common fields, I am able to access those values directly from the enum.

public enum CSSEntity: Equatable, Codable, Sendable {
    case dataset(DatasetRecord)
    case datasetSupplement(SupplementRecord)
    case master(MasterRecord)
    case masterSupplement(SupplementRecord)
    case primary(PrimaryRecord)
    case report(ReportRecord)
    case asset(AssetRecord)
    public var entityType: CSSEntityType {
        switch self {
        case .dataset: return .dataset
        case .datasetSupplement: return .datasetSupplement
        case .master: return .master
        case .masterSupplement: return .masterSupplement
        case .primary: return .primary
        case .report: return .report
        case .asset: return .asset
    /// Return the record with common fields identified
    var value: AnyDBObject {
        switch self {
        case .dataset(let datasetRecord):
            return datasetRecord
        case .datasetSupplement(let supplementRecord):
            return supplementRecord
        case .master(let masterRecord):
            return masterRecord
        case .masterSupplement(let supplementRecord):
            return supplementRecord
        case .primary(let primaryRecord):
            return primaryRecord
        case .report(let reportRecord):
            return reportRecord
        case .asset(let assetRecord):
            return assetRecord