> On Apr 12, 2017, at 11:44 AM, Russ Bishop via swift-evolution 
> <[email protected]> wrote:
> 
> * String and Int keys being optional, giving a CodingKey the opportunity to 
> return nil for both at runtime.

This was true in the first public draft, but I believe in this version 
`stringValue` is no longer Optional.

> * Encoder has three functions, but only one may ever be called. This API is 
> the opposite of "pit of success".

Personally, I'm worried about that too. But I had a lot of trouble coming up 
with an alternative that didn't violate a more important goal, like "being able 
to throw errors" or "being compatible with classes".

Last-ditch suggestion: Change a bunch of names so that, for instance, `Encoder` 
is instead `EncodingContainerizer`. (That's a terrible name, but "Factory" 
gives me the hives.) That way, the name of the type gives you a hint that 
you're supposed to use it to make a container. You might even rename the 
methods to e.g. `useContainer(keyedBy:)`, which sound a little more stateful 
and mutually-exclusive.

        func encode(to encoder: EncodingContainerizer) throws {
                var container = encoder.useContainer(keyedBy: CodingKeys.self)
                try container.encode(name, forKey: .name)
                try container.encode(birthDate, forKey: .birthDate)
        }

> I don't understand why KeyedEncodingContainer needs all those overloads; 
> automatic conformance to Encodable should be provided for the stdlib types in 
> those overloads so why would they be necessary?

I argued about this pretty vigorously. They want to avoid the overhead of 
building an encoder and single-value container and then making several generic 
calls to encode the value into the container. Personally, I think this is 
premature optimization of the highest order—particularly since building an 
encoder and single-value container are often no-ops—but this is the design they 
chose, and I don't think it's worth rejecting for that alone.

> KeyedEncodingContainer.encodeWeak seems like it should be a protocol 
> refinement so you can check for the capability (or potentially know at 
> compile time).

This probably ends up duplicating not only `KeyedEncodingContainerProtocol`,  
but also `UnkeyedEncodingContainer`, `Encoder`, and `Encodable`. Doable, yes. 
Worth it, especially when `encodeWeak` has a pretty sensible fallback behavior? 
Eh.

> (One minor bit of bike shedding: decode/decodeIfPresent could instead be 
> decode(required:) and decode(optional:)).

I don't think `required:` and `optional:` are really helpful. The name here is 
kind of like `addingWithOverflow(_:_:)`—you really want it to be `adding(x, y, 
.withOverflow)`, but it's not worth creating a dummy enum just to make a method 
read properly. Similarly, you'd like `decode(Int.self, .ifPresent)`, but the 
dummy's not worth the better readability.

I'm not sure why we don't do this, though:

        // Just showing Unkeyed for simplicity
        
        func decode<T: Decodable>(_ type: T.Type) throws -> T
        func decode<T: Decodable>(_ type: Optional<T>.Type) throws -> T?

        let alwaysInt = try container.decode(Int.self)
        let maybeInt = try container.decode(Int?.self)

> I really strongly dislike mixing up the Unkeyed and Keyed concepts. A type 
> should need to explicitly opt-in to supporting unkeyed and that should be 
> enforced at compile time. Unkeyed encoding is a potential versioning 
> nightmare and should be handled with care.

I think they've done a reasonable job of putting unkeyed coding in a sharps 
drawer by making you specifically ask for it and giving it an ugly name. 

> C#'s serialization attributes are a better and more comprehensive solution 
> but we don't have custom attributes in Swift and property behaviors were 
> deferred. This problem is too important to leave to the future though. If we 
> did ever add custom attributes or if property behaviors get implemented then 
> this design could adopt them incrementally without breaking compatibility 
> (e.g. a serialization transformer behavior that turns a non-Encodable 
> property into an Encodable one, or a behavior that ignores a property for 
> serialization purposes).

On the contrary, I think we *can* safely leave this to the future. If a future 
version of Swift and Foundation added:

        @uncoded var foo: Bar

That would be a completely additive change. Until then, there's an irritating 
but serviceable solution available—write your own CodingKeys enum and let code 
generation write the `Codable` conformances based on it.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to