To weigh in on the proposal itself: I think this is a solid approach for a quality-of-life improvement for those who have to work with serialization formats outside of their control, for which a lot of nesting makes nested types somewhat impractical. I did initially have two questions, which were answered by reviewing the implementation itself:
-
What is the underlying type of
CodingKeyPath.componentsgiven thatcomponentsis a type-erased[CodingKey]? These are given the concrete_CodingKeyPathComponentCodingKeytype, which can take on anyStringvalue -
Given that getting nested components requires concrete key types, how are you planning on fetching nested containers using type-erased
[CodingKey]lists? The coding keys become concrete_CodingKeyPathComponentkeys which can be used to decode
It would be nice for this to be spelled out a little bit more clearly in the pitch itself.
Overall, I prefer this approach to the Encoder/Decoder-specific approach: this design gives every Encoder and Decoder a free implementation, which is nice.
That being said, I will say that I am somewhat apprehensive about this on the whole:
-
For many developers,
CodingKeysand the implicit behavior around them can already at times be surprising and confusing, and I am somewhat worried that further expanding implicit behaviors with an additional approach can be even more confusing, especially since it will actually still be possible to defineenum CodingKeys: String, CodingKey { case nested = "my.nested.key" }but expect it to behave like a
CodingKeyPath.To that end, too: what happens if I define
enum CodingKeys: String, CodingKeyPath { ... }or
enum CodingKeyPaths: String, CodingKey { ... }by accident? Is there a way to simplify this current approach to make it more difficult (or ideally, impossible) to get wrong?
-
I'm slightly concerned about the use of "Key Path" in the name here, because of potential confusing with
KeyPaths, which are similar. (Indeed, we've had a few posts on the forums already in the past asking why we don't just useKeyPaths, the answer to which is that key paths don't map 1-to-1 withCodingKeys[you can haveCodingKeyswhich don't map to any property, for example, but not so withKeyPaths].)This is actually the reason why
EncoderandDecoderhave.codingPathrather than.codingKeyPath— to try to avoid some of the confusion of similar naming in similar-but-not-quite-aligning contexts.
These two concerns aren't a problem with your specific pitch, but are two areas that I think would need to have really compelling answers to make a change like this easier to swallow. Given that we already have solutions to this problem overall today (ideally, use nested types) and that it's relatively rare for those solutions to be sufficiently inconvenient to warrant this, I would personally want a solution in this area to significantly outweigh any potential confusion in order to be obviously appealing.