title: Encode/Decode Array of Types conforming to protocol with JSONEncoder
body: <p>I'm trying to find the best way to Encode/Decode an array of structs conforming to a swift protocol using the new JSONDecoder/Encoder in Swift 4.</p>
  
  <p>I made up a little example to illustrate the problem:</p>
  
  <p>First we have a protocol Tag and some Types that conform to this protocol.</p>
  
  <pre><code>protocol Tag: Codable {
      var type: String { get }
      var value: String { get }
  }
  
  struct AuthorTag: Tag {
      let type = "author"
      let value: String
  }
  
  struct GenreTag: Tag {
      let type = "genre"
      let value: String
  }
  </code></pre>
  
  <p>Then we have a Type Article which has an Array of Tags.</p>
  
  <pre><code>struct Article: Codable {
      let tags: [Tag]
      let title: String
  }
  </code></pre>
  
  <p>Finally we encode or decode the Article </p>
  
  <pre><code>let article = Article(tags: [AuthorTag(value: "Author Tag Value"), GenreTag(value:"Genre Tag Value")], title: "Article Title")
  
  
  let jsonEncoder = JSONEncoder()
  let jsonData = try jsonEncoder.encode(article)
  let jsonString = String(data: jsonData, encoding: .utf8)
  </code></pre>
  
  <p>And this is the JSON structure that I like to have.</p>
  
  <pre><code>{
   "title": "Article Title",
   "tags": [
       {
         "type": "author",
         "value": "Author Tag Value"
       },
       {
         "type": "genre",
         "value": "Genre Tag Value"
       }
   ]
  }
  </code></pre>
  
  <p>The problem is that at some point I have to switch on the type property to decode the Array but to Decode the Array I have to know its type.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>It's clear to me why Decodable can not work out of the box but at least Encodable should work. The following modified Article struct compiles but crashes with the following error message.</p>
  
  <pre><code>fatal error: Array&lt;Tag&gt; does not conform to Encodable because Tag does not conform to Encodable.: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.43/src/swift/stdlib/public/core/Codable.swift, line 3280
  
  struct Article: Encodable {
      let tags: [Tag]
      let title: String
  
      enum CodingKeys: String, CodingKey {
          case tags
          case title
      }
  
      func encode(to encoder: Encoder) throws {
          var container = encoder.container(keyedBy: CodingKeys.self)
          try container.encode(tags, forKey: .tags)
          try container.encode(title, forKey: .title)
      }
  }
  
  let article = Article(tags: [AuthorTag(value: "Author Tag"), GenreTag(value:"A Genre Tag")], title: "A Title")
  
  let jsonEncoder = JSONEncoder()
  let jsonData = try jsonEncoder.encode(article)
  let jsonString = String(data: jsonData, encoding: .utf8)
  </code></pre>
  
  <p>And this is the relevant part from Codeable.swift</p>
  
  <pre><code>guard Element.self is Encodable.Type else {
      preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Element.self) does not conform to Encodable.")
  }
  </code></pre>
  
  <p>Source: <a href="https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift" rel="noreferrer">https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift</a></p>