struct Person: Codable {
var name = ""
var age = 0
var sex = "male"
}
then:
Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "age", intValue: nil)], debugDescription: "Expected Int value but found null instead.", underlyingError: nil))
Can you make a mistake and go ahead? Why can't you go ahead?
Codable is the most difficult JSON parsing tool!!!!!!!!
struct Person: Codable {
var name: String
var age: Int?
var sex: String // probably the safest way to model this nowadays
}
let json = """
{
"name": "hello",
"age": null,
"sex": "male"
}
"""
let person = try? JSONDecoder().decode(Person.self, from: Data(json.utf8))
Your definition of Person looks like this:
struct Person: Codable {
var name = ""
var age = 0
var sex = "male"
}
Here, age is inferred to have the non-optional Int type – in other words, it has to be in the JSON, that’s why you get the error. (On the other hand, the synthesized decoding code could be smart enough to use the default value when not present in the JSON. @itaiferber, is there a reason for it not doing that?)
Codable is the most difficult JSON parsing tool!!!!!!!!
Swift is fairly strict, yes. It means more difficulties upfront and less difficulties in the long run. Sometimes it takes time to adjust to this tradeoff, but it’s worth it.
when you state var age = 0
compiler infers the type to be Int. 0 is Int.
But in JSON age is null, which can't be represented by Int. So decoding fails.
You've covered the other aspects of this question, but to answer this specifically:
Yes, largely the ambiguity of what default values might mean for decoding. For instance,
struct Widget: Codable, Equatable {
var name = "Default"
var identifier = UUID()
}
could have default values for the sake of synthesizing an init(name:identifier:), or it could be trying to indicate that if, say name were missing from the payload, "Default" would be a safe default value. The compiler can't guess at the intent here, and you can see the potential danger with falling back to identifier's default value: if the data is corrupted or missing, the Widget would silently "succeed" decoding with a completely new identity (and in this case, a universally unique one), and there'd be no way to recover from this. [There is no way to distinguish, after the fact, "was this value generated as the default, or was it correctly decoded from the payload?"]
It's significantly safer to fail the decoding process rather than allow silent data corruption to propagate in surprising ways — if developers prefer to use the default values, it's always possible to customize the behavior.
This is one way to spell it, yes. In general, there have been other considerations for "how do I override the behavior of decoding one property without having to override the whole initializer?", and adaptors have come up as a possible solution (e.g. offering ways to customize decoding on a per-property basis, allowing post-decoding transformations, etc.). It's reasonable that we could also spell "please use this default value" as one such adaptor.
However, what adaptors for Codable properties might look like, and what the feature would look like with Swift's current (or future) capabilities has not been fully explored.
One issue with an approach like this is that it's barely more convenient that writing out the full implementation explicitly (and not relying on synthesis in this class). Writing out the implementation has the benefit of making it 100% clear what your intentions are.
The only really hard part about "manual" implementation is remembering that it's not that hard to do.
this is that it's barely more convenient that writing out the full implementation
I disagree. Example above is very simple, with only two properties. Imagine case with several dozens of properties, and there is one array that is optional in json, but you have default value – empty array. You can write many lines of code, or three:
The only really hard part about "manual" implementation is remembering that it's not that hard to do.
We have hundreds or may be thousands loc of manual implementations. Yes, it is not hard, and very flexible. But sometimes such fallback seems very disappointing for small customisations. And sometimes, instead of implementing it manually, it just easier to reflect json structure and deal with its problems elsewhere.
But, I agree with itaiferber, it is not very appealing to constantly adding such customisation points at compiler level. Looks like more general approach must be taken.
This is pretty condescending; it's nice for you to help other people out, but please try to be patient with them when they're working through new ideas.