JSONDecoder, keyDecodingStrategy issue with Dictionary

I'm not sure about this, but maybe allowing modification of the decoder options during decoding (inside the init(from:) method) would solve this. Allowing this for all options would also address similar issues that might come up for the other options of JSONDecoder.

Example

The custom decoding code would look somehow like this:

init(from decoder: Decoder) throws {
    // decode things with the default key decoding strategy 
    // set key decoding strategy to the desired one, storing the old one
    // decoding in this example the dictionary
    // set strategy back to the old strategy
}

Implementation

  1. This could be implemented by either exposing _JSONDecoder and JSONDecoder._Options publicly and making options on _JSONDecoder a var.
  2. or by (hypothetically) storing the options inside userInfo (currently, it is the other way around) at a key like JSONDecoderOptions that would be defined by JSONDecoder and contained the _Options struct as value. However, this is purely theoretical, because Decoder has userInfo declared only as as get property. This approach also seems to turn around the sense of userInfo a bit, because here it's also information from the user to the decoder and not information purely for the user. However, I see this way as the most elegant one, but requiring either source breaking changes or additional API, like a options: [OptionKey : Any] { get set } property on Decoder with default implementations returning [:] and doing nothing.
  3. Forward changes on the options (would need to be public, other option properties would be removed) of JSONDecoder to _JSONDecoder. Every _JSONDecoder would store a reference to the JSONDecoder that created it and read those options or _Options would explicitly use reference semantics, such that _JSONDecoder and JSONDecoder could use the same _Options reference, both having own options properties. Making _Options would do this, I guess. In general, in this case there could be a bit additional confusion why I would need to store the JSONDecoder and access it in my init(from:) method somehow, if I get another decoder as argument anyway.

Alternative

This is a bit tricky alternative, that is already implementable today.
If one already made sure, that one is decoding from JSON, e.g. by checking a previously set key in userInfo, one decodes a JSONValue enum to get unevaluated information. Then one will convert this JSON types consumable by JSONSerialization, re-encode the unevaluated information and then pass this newly created JSON data to a new JSONDecoder with the desired options (concretely, a different key decoding strategy) and decode the type (dictionary here) with this JSONDecoder.

This might get a but easier with decoders providing unevaluated information directly, as discussed in New "Unevaluated" type for Decoder to allow later re-encoding of data with unknown structure, but allowing this has not been discussed now, as far as I know.

Because the re-encoding keys does not result in the same keys, as far as I can see, it is necessary to go over JSONSerialization here, I guess. One can use JSONEncoder to, if the used JSON implementation is Encodable, but this is actually one stage more.