You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[SR-5206] [Codable] The encoded results of Optional<URL> are different between Container.encode (_: ...) and Container.encodeIfPresent (_: ...) . #3846
On implementing Codable conformance, if it uses container.encode(_:…) instead of container.encodeIfPresent(_:…), container.encode(url, forKey: .url) produces dictionary. But, `JSONDecoder` tries to decode Optional<URL> from string.
Perhaps I think that this issue is caused by wrong usage of the API.
If Xcode can generate the same code as the Codable implementation generated by the compiler, such a mistake will decrease.
Unfortunately, this is expected behavior that we can't do much about. This is a consequence of not yet having conditional conformance in Swift — the compiler has no static guarantee that Wrapped is Encodable. Even though we can do a dynamic check, there is no way to force it statically so we can make the generic encode<T : Encodable>(_🙂 call. At best, we can cast the value to Encodable, but at that point, we've lost type information that it was Wrapped; the only thing we can then call is encode(to🙂 and pass the encoder in, but that never gives the container a chance to intercept and replace the value or change its format.
This will be resolved when we have conditional conformance and can make that static assertion.
This will be resolved when we have conditional conformance and can make that static assertion.
Hmm.
If type checking at runtime is required within the container implementation, it would be better to use encode(_: Encodable) rather than the generic encode<T: Encodable>(_:) I think.
@norio-nomura That would work on encode(), but not on decode(), which has to accept the type as an argument. It's better to be consistent so you can actually round-trip data, instead of being correct in only one direction.
@norio-nomura That looks... surprisingly reasonable. 🙂 I hadn't considered that, so thanks for pointing it out! I'll need to see how this plays with method dispatch (i.e. which overload of `SingleValueDecodingContainer.decode(_🙂` this will call for different types, or whether they'll always fall into the generic case). Unfortunately, we're past the deadline for the Swift 4.0 release for something like this, but this could be beneficial in an upcoming update.
@norio-nomura Glad this resolved the issue, and thank you for the suggestion! Unfortunately, though, we're past the deadline on fixes for Swift 4.0 except for the most critical of bug fixes... This will make it to the next dot release, though.
@itaiferber This issue seems to be critical for third party Encoders since it is hard to writing workaround code for third party Encoders.
If third party encoder does not write workaround, users of third party encoder will have to write migration code which will absorb the difference of behaviors of third party encoder before and after this issue correction in future releases. (Swift 4.0.1? 4.1?)
And I can not imagine how to migrate when deserializing serialized data before this problem is fixed in the fixed release. 🙁
Activity
norio-nomura commentedon Jun 13, 2017
@itaiferber Can you see this issue?
norio-nomura commentedon Jun 13, 2017
Perhaps I think that this issue is caused by wrong usage of the API.
If Xcode can generate the same code as the Codable implementation generated by the compiler, such a mistake will decrease.
itaiferber commentedon Jun 13, 2017
Unfortunately, this is expected behavior that we can't do much about. This is a consequence of not yet having conditional conformance in Swift — the compiler has no static guarantee that
WrappedisEncodable. Even though we can do a dynamic check, there is no way to force it statically so we can make the genericencode<T : Encodable>(_🙂call. At best, we can cast the value toEncodable, but at that point, we've lost type information that it wasWrapped; the only thing we can then call isencode(to🙂and pass the encoder in, but that never gives the container a chance to intercept and replace the value or change its format.This will be resolved when we have conditional conformance and can make that static assertion.
norio-nomura commentedon Jun 14, 2017
Hmm.
If type checking at runtime is required within the container implementation, it would be better to use
encode(_: Encodable)rather than the genericencode<T: Encodable>(_:)I think.itaiferber commentedon Jun 14, 2017
@norio-nomura That would work on
encode(), but not ondecode(), which has to accept the type as an argument. It's better to be consistent so you can actually round-trip data, instead of being correct in only one direction.norio-nomura commentedon Jun 15, 2017
Ah, I see. I didn't think about
decode().We will wait for the conditional conformance to come. 🙂
By the way, I filed a rdar://problem/32752900 as suggesting:
itaiferber commentedon Jun 15, 2017
@norio-nomura Thanks! We've got a Radar tracking that internally — hopefully we'll be able to get that in an upcoming version of Xcode.
itaiferber commentedon Jul 5, 2017
Looks like there is actually a (small, non-scalable) workaround for this in the meantime, at least for
JSONEncoderandJSONDecoder: PR-10766norio-nomura commentedon Aug 2, 2017
@itaiferber How about following workaround?
This would work with third party Decoders.
itaiferber commentedon Aug 2, 2017
@norio-nomura That looks... surprisingly reasonable. 🙂 I hadn't considered that, so thanks for pointing it out! I'll need to see how this plays with method dispatch (i.e. which overload of `SingleValueDecodingContainer.decode(_🙂` this will call for different types, or whether they'll always fall into the generic case). Unfortunately, we're past the deadline for the Swift 4.0 release for something like this, but this could be beneficial in an upcoming update.
itaiferber commentedon Aug 2, 2017
@norio-nomura This worked out surprisingly nicely, actually: PR-11315
norio-nomura commentedon Aug 4, 2017
@itaiferber I confirmed that this issue has been resolved on
swift-DEVELOPMENT-SNAPSHOT-2017-08-03-a. 😃Checking commits: jpsim/Yams@nn-SE-0166...nn-SR-5206
Build log on travis: https://travis-ci.org/jpsim/Yams/jobs/260850551
Thanks!
After all, is there no possibility that this fix will enter swift 4.0?
itaiferber commentedon Aug 4, 2017
@norio-nomura Glad this resolved the issue, and thank you for the suggestion! Unfortunately, though, we're past the deadline on fixes for Swift 4.0 except for the most critical of bug fixes... This will make it to the next dot release, though.
norio-nomura commentedon Aug 6, 2017
@itaiferber This issue seems to be critical for third party Encoders since it is hard to writing workaround code for third party Encoders.
If third party encoder does not write workaround, users of third party encoder will have to write migration code which will absorb the difference of behaviors of third party encoder before and after this issue correction in future releases. (Swift 4.0.1? 4.1?)
And I can not imagine how to migrate when deserializing serialized data before this problem is fixed in the fixed release. 🙁
norio-nomura commentedon Aug 9, 2017
@itaiferber I would like to guard my tests by using {{#if swift()}} until this fix will be released. What version will this fix include? 4.0.1 or 4.1?
norio-nomura commentedon Nov 1, 2017
I confirmed that this issue has been fixed on Xcode 9.2 beta (9C32c). 👍
itaiferber commentedon Nov 2, 2017
@norio-nomura Thanks for confirming! 🙂