Roundtripping key coding strategies

Thanks for bringing this back up, Morten. I think my gut feeling has remained the same since last time:

From a principled standpoint (at least for me), adjusting the raw values of a type's CodingKeys to match what a single encoder does isn't (or shouldn't be) the right approach. Unless one overrides the Codable methods to use multiple pairs of keys, they're reused for all types — which means that a "quick" adjustment today to "fix" the results from JSON{En,De}coder means that you propagate this weirdness to other formats/encoders.

To answer your questions, from my perspective:

  1. Yes, I think this issue warrants fixing
  2. I believe the issue can be fixed in Foundation alone. Details below
  3. I don't believe fixes would need to apply to the standard libraries; this is really between a type and JSON{En,De}coder

I haven't had the opportunity to think this through entirely, but a thought: back in the mists of time, @Tony_Parker and I discussed the possibility of having JSON{En,De}coder build in a list of known abbreviations which we could correctly identify as terms which would be correctly cased ("HTML", "URL", etc.) with the default .convert{To,From}SnakeCase strategies, but didn't get to explore this idea at the time. I wasn't a fan of having Foundation hard-code a list of known values like this, and I still don't, but luckily it could be easy to extend to users:

enum JSONDecoder.KeyDecodingStrategy {
    // ...

    // Not entirely thought through: some options to maybe allow/ignore
    // recognition at the beginning of a case name, like
    // `htmlForURL` vs. `HTMLForURL`
    case convertFromSnakeCaseWithKnownAbbreviations(Set<String>, options: SomeOptionType)

    // ...
}

Sadly, I don't believe adding associated values to existing enum cases is ABI-stable, or else we could do something like

enum JSONDecoder.KeyDecodingStrategy {
    case convertFromSnakeCase(knownAbbreviations: Set<String> = [], options: SomeOptionType = .default)
}

to maintain source stability, and not have to come up with a new case entirely.

Either way, this could give users an "in" to provide abbreviations their CodingKeys use across an entire payload, and theoretically, they could revert changes to their CodingKeys' raw values.

It would be up to them to scan through their CodingKeys to find these abbreviations, or Foundation could provide at least a default list (JSONDecoder.KeyDecodingStrategy.defaultKnownAbbreviations?) that could be extended with additional values before being passed in to the enum case. (I can see folks cargo-culting a "preferred" list of abbreviations either way, regardless of application, but I don't think that's worth worrying about.)


I haven't had time to fully think through this idea or its implications, so please poke holes if this obviously won't work for some reason, but I think this might be at least a compelling place to start exploring a fix in a contained way.

(Sadly, this does leave other encoders/decoders in the lurch if users have already adjusted CodingKeys for this purpose and used them for other formats — but my gut feeling is that fixing the issue "at the source" might be a good start.)

4 Likes