Uploaded image for project: 'Swift'
  1. Swift
  2. SR-7566

Improve handling/synthesis of Protocols that are Codable

    XMLWordPrintable

    Details

    • Type: Improvement
    • Status: Resolved
    • Priority: Medium
    • Resolution: Won't Do
    • Component/s: Compiler
    • Labels:

      Description

      If a Codable Type has a Protocol property that is also Codable, encoding/decoding requires a significant amount of boilerplate code and/or changing the Protocol property to instead be a Type Erasure property.

      Root issue being that a Protocol does not conform to itself, so the Protocol property does not itself conform to Codable. This blocks the Codable synthesis of the parent class.

      There is also the additional problem of needing to encode/decode unique properties of each Protocol adoptee.

      The solutions to this issue are outlined in the excellent answer here:
      https://stackoverflow.com/a/44473156/1265393

      • The Codable Protocol Property in the parent object can be changed to a Codable Type Erasure, with additional code to handle the unique properties of each Protocol member type.
      • Optionally, the parent object can transform the property to the type erasure in its encode/decode methods so that the original property can remain of the Protocol Type.

      Opening this improvement ticket for a future version of Swift to hopefully synthesize or otherwise automatically handle Codability of Protocol properties.

      Example of issue for playground:

      struct Library: Codable {
          let books: [Book]   // ok
          let movies: [Movie] // ok
          
          let typeErasure: [AnyMedia] // ok, at least Codable for the Protocol/AnyProtocol Properties.
          
          let mediaItems: [Media]
          // Error: cannot automatically synthesize 'Encodable' because '[Media]' does not conform to 'Encodable'
          // Error: cannot automatically synthesize 'Decodable' because '[Media]' does not conform to 'Decodable'
          
          init(book: Book, movie: Movie) {
              books = [book]
              movies = [movie]
              
              let media: [Media] = [book, movie]
              mediaItems = media
              typeErasure = media.map( { AnyMedia(title: $0.title) } )
          }
      }
      
      protocol Media: Codable {
          var title: String { get }
      }
      
      struct Book: Media, Codable {
          let title: String
      }
      
      struct Movie: Media, Codable {
          let title: String
      }
      
      struct AnyMedia: Media, Codable { // Type Erasure
          let title: String
      
           // Additional code would encode/decode any unique properties of each Protocol adoptee.
      }
      
      let book: Book = Book(title: "The Hobbit")
      let movie: Movie = Movie(title: "Star Wars")
      let library = Library(book: book, movie: movie)
      

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              pkamb Peter Kamb
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: