Bug or PEBKAC?

I'm not sure it needs to be that complicated.

Currently, if the JSONEncoder detects a [String: Encodable] dictionary, it manually iterates the key-value pairs, encodes the value, and places the result in an NSMutableDictionary.

It should be possible to instead:

  • iterate the key-value pairs
  • encode the key in to a separate container
  • validate that the container holds exactly one String (however deeply nested it may be)
  • associate that String with the value in the resulting NSMutableDictionary.

This would naturally allow all other primitive types (like Date), as well as single-item arrays of primitives, to be encoded when they are used as dictionary keys. The important thing is that your key-type boils down in to a single String when encoded. That seems like a more reasonable limitation, based on how your values encode relative to the JSON spec, rather than how you model them in the Swift type system (which really has nothing at all to do with JSON).

JSONDecoder similarly detects dictionaries, so we can create a custom Decoder which does the reverse: it only has a single String, so any object-graph you inflate from it can only decode a single value, however deeply-nested it may be. That's simple enough to validate.

I have a rough patch which does that, and it appears to work without regressing anything in the test suite. I'll need to check a bunch of edge-cases before it's ready for a PR though (not that I expect it to ever be merged).

1 Like

If I've understood you correctly, this does sound like the original approach I tried to imply (and I believe I misunderstood your follow-up response): if you encode the key it's trivial to check if the encoded value boils down to a String/Int, you just have to check after it's done encoding. With additional state, it's possible to confirm this before it's done encoding, but this can get messy.

The original point in context was simply that there's no way to guess up-front: either way, you have to start encoding the key in order to find out (and at that point, you have to let the key finish encoding fully before checking further keys).

1 Like

just hit this bug today. so unfortunate it's still unfixed. it really feels like bug, even that now i know that encoding dictionaries as lists in some cases was implemented on purpose (IMHO that's unnecessary and plain wrong). i support the idea of having an opt-in for a correct behaviour in a form of a new "StringKeyRepresentable" protocol.

Hi @tera,

It would be great if you could voice your support on the pitch thread here:

The corresponding proposal is written, and a member of the Swift Core Team did assign themselves to the proposal PR. :slight_smile:

Sincerely,
/Morten