I think we should avoid cluttering up variable declarations with attributes as much as possible. They make code harder to read and reason about, and would scatter the information relevant to Codable throughout the type declaration.
(One exception is a @transient attribute, to exclude a property from automatic synthesis for Equatable, Hashable, and Codable alike.)
For more fine-grained control over encoding and decoding, I would greatly prefer to encapsulate the annotations within the type’s CodingKeys, and let the compiler synthesize the rest. Here is a brief sketch of what that might look like:
First, make it possible to declare CodingKeys as conformng to a marker protocol (eg. Synthesized or Automatic or suchlike), so it can be present without removing compiler synthesis.
Next, introduce annotations for customizing the implementation of encoding / decoding. I don’t know exactly what this would look like, but here’s a conceptual idea:
struct Foo {
var bar: Int
var baz: Double
@transient var cache: String?
enum CodingKeys: Synthesized {
case bar(VerboseKey("monkey"))
}
}
From a user perspective, this should act like there is a nested enum, eg. Foo.CodingKeys.RealCodingKeys. Or maybe instead of declaring CodingKeys, one instead declares CodingKeyCustomization and the compiler synthesizes CodingKeys. In any case, the compiler synthesizes the coding keys that actually get used.
The example uses VerboseKey, which is my first attempt at allowing different encoders (eg. JSON) to choose keyed vs. unkeyed, rather than having Foo make a single decision for all encodings. So perhaps the compiler synthesizes two enums, one for verbose keys and one not.
JSON could prefer verbose keys when they are available, and binary formats could prefer non-verbose. This might be the wrong approach here, I don’t know. But the idea is to let the author of Foo provide information about its coding keys that encoders can utilize, while still benefitting from compiler synthesis.
The specifics about what can be customized and how, would need to be nailed down. However, I think it is best to keep all such customization grouped together in one place, rather than scattered throughout the type itself.