I don't totally agree that Codable
is an effort to serialise a type to multiple formats. Ideally, looking at Codable
without any custom codable functions, it is really an effort to serialise to and from a single format: key-value coded Swift structs.
The problem with Codable
– and what I think you're getting at when you suggest we need JSONCodable
/PlistCodable
– is there's no sane custom implementation of init(from:)
and encode(to:)
without being archive-specific. These functions are generally a mashup of two different ideas:
- migration and versioning
- archive-specific choices like which fields to include and what order
But moreover, while you might make archive-specific choices, you don't always have archive-specific knowledge. Take for example, trying to decode a value from an archive that might include any common "property tree" value:
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self = .null
} else if let stringValue = try? container.decode(String.self) {
self = .string(stringValue)
} else if let intValue = try? container.decode(Int.self) {
self = .integer(intValue)
} else if let doubleValue = try? container.decode(Double.self) {
self = .double(doubleValue)
} else if let boolValue = try? container.decode(Bool.self) {
self = .boolean(boolValue)
} else if let array = try? container.decode([DatabaseLiteralValue].self) {
self = .array(try JSONEncoder().encode(array))
} else {
self = .object(try JSONEncoder().encode(container.decode([String: DatabaseLiteralValue].self)))
}
}
We have no lookahead. We can't peek to see if the next char is a double-quote, a digit or a bracket. Without overloading the Decoder
to emit lookahead metadata as decodable types, you simply need to try each possibility, in turn, incurring the overhead and disruption of thrown errors.
I'd hope the visitor pattern here would be able to come back and say: I've already decoded the Bool
type and just eliminate this need for archive-specific knowledge and ad-hoc parsing within the Decoding
implementation.