-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Swift Archival & Serialization API #9004
Swift Archival & Serialization API #9004
Conversation
Add Encodable and Decodable protocols, along with associated container types, default implementations, and extensions to the standard library
* Allow CodingKey conformance to be automatically derived for enums which have no raw type (with no associated values) and which have a raw type of String or Int. * Allow Encodable and Decodable conformance to be automatically derived for classes and structs with Encodable/Decodable properties * Add initial unit tests for verifying derived conformance
Since all of the core types are now in the Swift stdlib, the tests no longer rely on objc_interop or Foundation.
@swift-ci Please test |
Build failed |
Build failed |
I'm not sure these test failures are actually related to my changes. On Linux we're getting failures like |
Let's try again |
@swift-ci Please test |
Build failed |
Build failed |
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type. | ||
/// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key. | ||
/// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key. | ||
func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@itaiferber great proposal, can't wait to start using this. But I have a question: wouldn't be better to drop the type from the parameters and just use inference here? Something like:
func decode<T : Decodable>(_ key: Key) throws -> T
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Obitow Thanks!
This point has been discussed at length on swift-evolution; dropping the type parameter can lead to ambiguous statements, which can be confusing and unintuitive. Please feel free to refer to those discussions for the full story.
Perhaps we can try the smoke tests at least? |
@swift-ci Please smoke test |
It's possible that |
@swift-ci Please test |
Build failed |
Looks like the |
Build failed |
struct X : Codable {} should generate an encode(to:) which encodes an empty keyed container, not an encode(to:) which does nothing
Extensions need not have nominal types, e.g. extension Int : Codable { ... } where typealias Codable = Encodable & Decodable
@swift-ci Please test |
Build failed |
It seems like a bug like this in the actual AST (e.g., duplicated initializers) would cause everything to break horribly, so it feels like a SourceKit bug. |
You shouldn't need to be Codable in order to get these implementations; being either Encodable or Decodable should be enough to get the relevant default implementation
This last commit doesn't fix the issue, but if I'm already looking at the extensions... (Let's split them up so you can benefit even by just being |
/// | ||
/// - parameter lhs: The key to compare against. | ||
/// - parameter rhs: The key to compare with. | ||
public static func ==(_ lhs: CodingUserInfoKey, _ rhs: CodingUserInfoKey) -> Bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd meant to split this out into a different commit, but it made it in here anyway. CodingUserInfoKey
was missing ==
, but the compiler didn't complain.
Per @akyrtzi's suggestion via email, going to update the test to prevent this from blocking us and file a Radar about it. |
@swift-ci Please test |
Build failed |
Build failed |
Build failed with an unrelated issue that's been reverted; let's try again. |
@swift-ci Please test |
For interested Apple folks, BTW, rdar://31896858 |
Build failed |
Looks like a Migrator test is failing for the iOS simulator: |
The builder is producing a module file for the incorrect target? |
@shahmishal @DougGregor This... Seems wrong. Any idea why this might happen? |
Seems like https://ci.swift.org/view/Pull%20Request/job/swift-PR-osx/ failed with this as well... |
Waiting on #9113 before testing again. |
Let's try that again |
@swift-ci Please test |
Excellent. @parkera @DougGregor If either of you sees this, can you please merge it in? |
Thanks @DougGregor! |
|
||
// An implementation of _KeyedEncodingContainerBase and _KeyedEncodingContainerBox are given at the bottom of this file. | ||
/// `KeyedEncodingContainer` is a type-erased box for `KeyedEncodingContainerProtocol` types, similar to `AnyCollection` and `AnyHashable`. This is the type which consumers of the API interact with directly. | ||
public struct KeyedEncodingContainer<K : CodingKey> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@itaiferber Should KeyedEncodingContainer
declare KeyedEncodingContainerProtocol
conformance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can, but I don't see much of a benefit to doing so. When would you want to use it as KeyedEncodingContainerProtocol
instead of the fully-typed KeyedEncodingContainer<K>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, you are right. I can not think of such a scene.
I just wondered watching KeyedDecodingContainer
declared asKeyedDecodingContainerProtocol
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch — I don't think that's really necessary either. It doesn't hurt, but we should be consistent. I'll consider this; thanks!
stdlib/public/core/Codable.swift
Outdated
|
||
/// Decodes a value of the given type for the given key, if present. | ||
/// | ||
/// This method retu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@itaiferber Why is it mutating
only for decode()
of UnkeyedDecodingContainer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UnkeyedDecodingContainer
s need to maintain some form of state to keep track of where they are in decoding, whether an index into an array that's incrementing with every decode(...)
call, an offset into a data blob or stream, etc. The methods are mutating
to indicate that, and to allow the implementation to be a struct
. This is as opposed to KeyedDecodingContainer
s and SingleValueDecodingContainer
s, which by design will almost certainly not need to do that. Is there a use case you have in mind for making those mutating
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly, I could not think of any reason to make decode()
of another protocol mutating
as well.
Thank you for answering my boring questions. 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at all! Thank you for paying such close attention to this; it's the best way for us to get direct feedback on it, and I appreciate your efforts. 😄
I filed SR-4861 that request adding |
@norio-nomura Thanks, assigned that to myself. That change, among a few others, is planned, and going through some API review soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All committed changes appear correct after review.
let _ = SimpleChildClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}} | ||
|
||
// The enum should have a case for each of the vars. | ||
// NOTE: This expectedxerror will need to be removed in the future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small text fix needed in comment. "//NOTE: This expected error will need to be removed in the future."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! #16749
What's in this pull request?
Now that the core types introduced by SE-0166 have been sunk into the Swift standard library, the stdlib and compiler portions of #8124 and #8125 can be combined into one PR (this one).
The features can be tested together; #8125 was previously not tested on its own since it required the presence of #8124.
The Foundation portions of #8124 will be put up in a subsequent PR.
rdar://problem/30472044