Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-7566] Improve handling/synthesis of Protocols that are Codable #50108

Closed
swift-ci opened this issue Apr 29, 2018 · 3 comments
Closed

[SR-7566] Improve handling/synthesis of Protocols that are Codable #50108

swift-ci opened this issue Apr 29, 2018 · 3 comments
Labels
Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself improvement

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-7566
Radar None
Original Reporter pkamb (JIRA User)
Type Improvement
Status Resolved
Resolution Won't Do
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Improvement, Codable
Assignee None
Priority Medium

md5: fe10b8d6c86530b0815424131ee13283

Issue 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)
@belkadan
Copy link
Contributor

belkadan commented May 1, 2018

This request ultimately doesn't make sense because of what happens on the decode side. Unlike NSCoding, Codable doesn't include any information about the type of a value in the encoded representation. That means you can't actually decode the data, because you don't know what dynamic type to use.

Type erasure works with Encodable, but even there you lose out on possible specialized representations for a particular value—for instance, a string-keyed dictionary and an "AnyEncodable"-keyed dictionary are encoded differently, even if the AnyEncodable values all happen to be strings.

@itaiferber can explain further if you have more questions.

@swift-ci
Copy link
Collaborator Author

swift-ci commented May 1, 2018

Comment by Peter Kamb (JIRA)

Yeah, I understand why it doesn't / won't work with the current implementation of Codable.

But this seems like a pretty severe limitation in our "protocol-oriented programming language"...?

This basically makes it extremely complicated / untenable to use Protocols in data models.

Codable and Protocols are both pretty basic Swift building blocks, but using them together results in a nasty rabbit hole of type erasure, broken Codable synthesis, dynamic types, etc. No way to eliminate that hurdle?

@swift-ci
Copy link
Collaborator Author

swift-ci commented May 1, 2018

Comment by Peter Kamb (JIRA)

It feels like this could "just work" via the introduction of synthesized code that replicated the approach taken in the Stack Overflow answer. Perhaps with a single required enum that mapped keys to decodable types.

enum MediaType : String, Codable {
    case book
    case movie

    var metatype: Tag.Type {
        switch self {
        case .book:  return Book.self
        case .movie: return Movie.self
        }
    }
}

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself improvement
Projects
None yet
Development

No branches or pull requests

2 participants