1
import Foundation

protocol ProtocolA: Codable {
    var var1: String { get }
}

struct Type1: ProtocolA {
    var var1: String
    var var2: Int
}

struct Type2: ProtocolA {
    var var1: String
    var var2: Bool
}

func encode<T: ProtocolA & Encodable>(object: T) throws -> Data {
    return try JSONEncoder().encode(object as! T.Type)
}

Putting the above in a playground results in error: argument type 'T.Type' does not conform to expected type 'Encodable'

Why does this happen when I am saying that T has to conform to Encodable?

abcross92
  • 33
  • 5

2 Answers2

3
return try JSONEncoder().encode(object as! T.Type)

This means to convert object to the metatype of T. The type of the type. For example, 1 is an Int. But "Int" itself has a type, which is Int.Type, which is a metatype. Metatypes do not conform to Encodable.

You meant:

return try JSONEncoder().encode(object as! T)

But you really just meant:

return try JSONEncoder().encode(object)

since object is always of type T. That's its explicit type from the function signature. Since you also don't rely on ProtocolA for this algorithm, this all boils down to:

func encode<T: Encodable>(object: T) throws -> Data {
    return try JSONEncoder().encode(object)
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Ok thanks that makes sense. What I'm really trying to achieve is: `struct Container: Codable {var array: [ProtocolA] }` Without having to switch over all the types that conform to that protocol in the `encode(to encoder:)` and `init(from decoder:)` methods – abcross92 Nov 16 '19 at 02:38
1

Your compiler is actually complaining about the type cast your doing at the end which is converting object to the metatype of T, in your example either Type1.Type or Type2.Type.

From the encoding perspective, what the compiler needs to know is the model confirms to Encodable which is implicit in the T: Codable statement.

import Foundation

protocol ProtocolA: Codable {
    var var1: String { get }
}

struct Type1: ProtocolA {
    var var1: String
    var var2: Int
}

struct Type2: ProtocolA {
    var var1: String
    var var2: Bool
}

func encode<T: Codable>(object: T) throws -> Data {
    return try JSONEncoder().encode(object)
}

let type2 = Type2(var1: "test1", var2: true)

print(type2)
Awad
  • 823
  • 3
  • 11
  • 33