# Protocol types vs generics (or: encoding an Encodable)

**URL:** <https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180>\
**Category:** Using Swift\
**Tags:** generics\
**Created:** [April 26, 2018, 7:24pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180 "2018-04-26T19:24:10Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![svanimpe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/svanimpe/32/38963_2.png) [@svanimpe](https://forums.swift.org/u/svanimpe)\
**Post date:** [April 26, 2018, 7:24pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/1 "2018-04-26T19:24:10Z")

</div>

I would like to encode multiple encodables and merge the results. Something like:

```swift
func encodeAndMerge(_ values: Codable...) throws -> [String: Any] {
    var result: [String: Any] = [:]
    for value in values {
        let data = try JSONEncoder().encode(value)
        let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
        result.merge(json, uniquingKeysWith: { $1 })
    }
    return result
}

```

However, this doesn't work as protocols don't conform to themselves.

Is there a clean solution to this problem?

By clean I mean not using multiple overloads with copy/pasted code, like this:

```swift
func encodeAndMerge<T: Codable, U: Codable>(_ first: T, _ second: U) throws -> [String: Any] {
    var result: [String: Any] = [:]
    
    let firstData = try JSONEncoder().encode(first)
    let firstJSON = try JSONSerialization.jsonObject(with: firstData, options: .allowFragments) as! [String: Any]
    result.merge(firstJSON, uniquingKeysWith: { $1 })
    
    let secondData = try JSONEncoder().encode(second)
    let secondJSON = try JSONSerialization.jsonObject(with: secondData, options: .allowFragments) as! [String: Any]
    result.merge(secondJSON, uniquingKeysWith: { $1 })
    
    return result
}

// and so on for 3, 4, ... parameters

```

---

<div class="post-metadata">

**Author:** ![mpangburn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mpangburn/32/45144_2.png) [@mpangburn](https://forums.swift.org/u/mpangburn)\
**Post date:** [April 26, 2018, 7:53pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/2 "2018-04-26T19:53:44Z")

</div>

If you're trying to encode multiple values of different types conforming to `Encodable`, the feature you're looking for is called [variadic generics](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#variadic-generics), which is not yet implemented.

If you're trying to encode multiple values all of the same type conforming `Encodable`, the solution is somewhere between what you've written as your two code samples:

```swift
func encodeAndMerge<T: Encodable>(_ values: T...) throws -> [String: Any] { /* ... */ }

```

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 27, 2018, 1:08am UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/3 "2018-04-27T01:08:09Z")

</div>

This package seems like it could help:

> **[GitHub - Flight-School/AnyCodable: Type-erased wrappers for Encodable,...](https://github.com/Flight-School/AnyCodable)**
>
> Type-erased wrappers for Encodable, Decodable, and Codable values - GitHub - Flight-School/AnyCodable: Type-erased wrappers for Encodable, Decodable, and Codable values

It should let you write the method as `func encodeAndMerge(_ value: AnyCodable...) throws -> [String: Any] { ... }`, with an implementation mostly identical to the example you included.

---

<div class="post-metadata">

**Author:** ![svanimpe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/svanimpe/32/38963_2.png) [@svanimpe](https://forums.swift.org/u/svanimpe)\
**Post date:** [April 28, 2018, 12:23pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/4 "2018-04-28T12:23:14Z")

</div>

Thanks Michael.

I didn't know about variadic generics yet, but now I know I want them 🙂

---

<div class="post-metadata">

**Author:** ![dabby](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dabby/32/7221_2.png) [@dabby](https://forums.swift.org/u/dabby)\
**Post date:** [April 26, 2019, 1:42pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/5 "2019-04-26T13:42:54Z")

</div>

I'm not sure the reason behind this, but wrapping each value in an "AnyEncodable" box will get you what you want.

By "AnyEncodable", I mean something like this:

```swift
struct AnyEncodable: Encodable {
	let value: Encodable

	func encode(to encoder: Encoder) throws {
		try value.encode(to: encoder)
	}
}

```

You can then use it in your `encodeAndMerge` function:

```swift
func encodeAndMerge(_ values: Codable...) throws -> [String: Any] {
	let encoder = JSONEncoder()
	let result: [String: Any] = try values.reduce([String: Any]()) { runningResult, codable in
		let data = try encoder.encode(AnyEncodable(value: codable))
		guard let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
			return runningResult
		}
		return runningResult.merging(json, uniquingKeysWith: { $1 })
	}
	return result
}

```

Without the box, Swift will give an error:  
`error: protocol type 'Codable' (aka 'Decodable & Encodable') cannot conform to 'Encodable' because only concrete types can conform to protocols` which is what I'm guessing you were getting in your code...

But I don't know exactly why it allows initializing `AnyEncodable(value: Encodable)` with a protocol type.

Hope this helps.

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [April 26, 2019, 5:13pm UTC](https://forums.swift.org/t/protocol-types-vs-generics-or-encoding-an-encodable/12180/6 "2019-04-26T17:13:24Z")

</div>

Note that this has been discussed in other threads (namely, [How to encode objects of unknown type?](https://forums.swift.org/t/how-to-encode-objects-of-unknown-type/12253)), and an implementation which does

```swift
func encode(to encoder: Encoder) throws {
    try value.encode(to: encoder)
}

```

won't quite give you what you want in all cases because it doesn't give an `Encoder` a chance to intercept the value before it encodes its contents. This is important for encoding strategies to apply (e.g. `JSONEncoder.dateEncodingStrategy`), which means that you could have inconsistent application of the strategy across your archive. [@hamishknight's approach](https://forums.swift.org/t/how-to-encode-objects-of-unknown-type/12253/5) approach will more consistently give you the results you're looking for.
