Another issue of scale - I had to switch to a native mail client as replying inline severely broke my webmail client. ;-)
Again, lots of love here. Responses inline. > On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution > <[email protected]> wrote: > Proposed solution > We will be introducing the following new types: > > protocol Codable: Adopted by types to opt into archival. Conformance may be > automatically derived in cases where all properties are also Codable. FWIW I think this is acceptable compromise. If the happy path is derived conformances, only-decodable or only-encodable types feel like a lazy way out on the part of a user of the API, and builds a barrier to proper testing. > [snip] > > Structured types (i.e. types which encode as a collection of properties) > encode and decode their properties in a keyed manner. Keys may be > String-convertible or Int-convertible (or both), and user types which have > properties should declare semantic key enums which map keys to their > properties. Keys must conform to the CodingKey protocol: > public protocol CodingKey { <##snip##> } A few things here: The protocol leaves open the possibility of having both a String or Int representation, or neither. What should a coder do in either case? Are the representations intended to be mutually exclusive, or not? The protocol design doesn’t seem particularly matching with the flavor of Swift; I’d expect something along the lines of a CodingKey enum and the protocol CodingKeyRepresentable. It’s also possible that the concerns of the two are orthogonal enough that they deserve separate container(keyedBy:) requirements. Speaking of the mutually exclusive representations - what above serializations that doesn’t code as one of those two things? YAML can have anything be a “key”, and despite that being not particularly sane, it is a use case. > For most types, String-convertible keys are a reasonable default; for > performance, however, Int-convertible keys are preferred, and Encoders may > choose to make use of Ints over Strings. Framework types should provide keys > which have both for flexibility and performance across different types of > Encoders. It is generally an error to provide a key which has neither a > stringValue nor an intValue. > Could you speak a little more to using Int-convertible keys for performance? I get the feeling int-based keys parallel the legacy of NSCoder’s older design, and I don’t really see anyone these days supporting non-keyed archivers. They strike me as fragile. What other use cases are envisioned for ordered archiving than that? > [snip] > > Keyed Encoding Containers > > Keyed encoding containers are the primary interface that most Codable types > interact with for encoding and decoding. Through these, Codable types have > strongly-keyed access to encoded data by using keys that are semantically > correct for the operations they want to express. > > Since semantically incompatible keys will rarely (if ever) share the same key > type, it is impossible to mix up key types within the same container (as is > possible with Stringkeys), and since the type is known statically, keys get > autocompletion by the compiler. > > open class KeyedEncodingContainer<Key : CodingKey> { Like others, I’m a little bummed about this part of the design. Your reasoning up-thread is sound, but I chafe a bit on having to reabstract and a little more on having to be a reference type. Particularly knowing that it’s got a bit more overhead involved… I /like/ that NSKeyedArchiver can simply push some state and pass itself as the next encoding container down the stack. > open func encode<Value : Codable>(_ value: Value?, forKey key: Key) throws Does this win anything over taking a Codable? > open func encode(_ value: Bool?, forKey key: Key) throws > open func encode(_ value: Int?, forKey key: Key) throws > open func encode(_ value: Int8?, forKey key: Key) throws > open func encode(_ value: Int16?, forKey key: Key) throws > open func encode(_ value: Int32?, forKey key: Key) throws > open func encode(_ value: Int64?, forKey key: Key) throws > open func encode(_ value: UInt?, forKey key: Key) throws > open func encode(_ value: UInt8?, forKey key: Key) throws > open func encode(_ value: UInt16?, forKey key: Key) throws > open func encode(_ value: UInt32?, forKey key: Key) throws > open func encode(_ value: UInt64?, forKey key: Key) throws > open func encode(_ value: Float?, forKey key: Key) throws > open func encode(_ value: Double?, forKey key: Key) throws > open func encode(_ value: String?, forKey key: Key) throws > open func encode(_ value: Data?, forKey key: Key) throws What is the motivation behind abandoning the idea of “primitives” from the Alternatives Considered? Performance? Being unable to close the protocol? What ways is encoding a value envisioned to fail? I understand wanting to allow maximum flexibility, and being symmetric to `decode` throwing, but there are plenty of “conversion” patterns the are asymmetric in the ways they can fail (Date formatters, RawRepresentable, LosslessStringConvertible, etc.). > /// For `Encoder`s that implement this functionality, this will only > encode the given object and associate it with the given key if it encoded > unconditionally elsewhere in the archive (either previously or in the future). > open func encodeWeak<Object : AnyObject & Codable>(_ object: Object?, > forKey key: Key) throws Is this correct that if I send a Cocoa-style object graph (with weak backrefs), an encoder could infinitely recurse? Or is a coder supposed to detect that? > open var codingKeyContext: [CodingKey] > } > [snippity snip] > Alright, those are just my first thoughts. I want to spend a little time marinating in the code from PR #8124 before I comment further. Cheers! I owe you, Michael, and Tony a few drinks for sure. Zach Waldowski [email protected]
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
