-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: encoding/json: dynamic field omission #52803
Comments
see also #50480 |
I like what's proposed in #50480, but the implementation was considerably easier for this proposal as we can leverage the code next to https://cs.opensource.google/go/go/+/refs/tags/go1.18.1:src/encoding/json/encode.go;l=750 |
Personally, I think it might make more sense to add a method like The other nice thing is it side-steps the issue of what happens when you directly pass your custom type to |
@rittneje Thanks for the feedback. IMHO, the concept of a property being "empty" seems to be a flawed abstraction. True, we do have existing patterns around "emptiness" (omitempty etc.). Here I'm making that claim that the model that we use to describe a json document should more clearly expose the concept of "property omission" to the object model. Though, to directly answer your question, I would expect |
I see "helpers" like We should have a way to describe a policy around property omission without making assumptions around policy as property omission is a core part of the json data structure. With this policy-based view in mind, we would then be able to phrase the policy of function (x Foo) Omitted() (bool, error){
switch reflect.TypeOf(x){
case reflect.String:
return x == ""
case reflect.Int:
return x == 0
case reflect.Ptr:
return x == nil
...
}
} |
/cc @dsnet |
This proposal has been added to the active column of the proposals project |
This feels like a duplicate of #45669. A prototype implementation of #45669 supports an
This definition is simple to implement and easy to explain. |
I implemented a prototype of the approach similar to #45669 for #11939 in CL 13977, though it applies to Another option oft-mentioned in other proposals would be to add a sentinel error value to indicate that a value should be omitted from the |
Is the benefit over #50480 just an easier implementation? |
The difficulty lies not with the implementation, which is rather straightforward. The difficulty is in the details and making sure it interacts well with the overall ecosystem. The
are not acceptable approaches. Also, we can't change the meaning of |
Potential issues with using
|
@joeshaw: Thanks. Those are legitimate concerns, but what you're suggesting is getting increasingly more complicated. The more complicated the rules, the harder it is to use correctly. If we go with a more complicated definition of what "zero" means, anything about being "exported" should not appear in the definition. It seems the intent is not so much that we should ignore unexported fields, but rather that we should ignore fields that have no JSON serialization. It would be odd to ignore an unexported field, but consider the zero-ness of a field marked as Using |
What if, instead of a sentinel error, there was a sentinel value. func (x T) MarshalJSON() ([]byte, error) {
return json.Empty, nil
} Where var Empty = []byte("null") |
That's an interesting idea, but it assumes that the output of |
I'm not sure why sentinel errors aren't acceptable? Callers should be handling errors, and any old caller code used with new MarshalJSON code should just surface it (fail) as another error, which can prompt people to update caller code. |
@dsnet could it be good that the caller is able to mutate and thus block (if they so choose) this behavior? |
Returning a sentinel error value here indicates behavior, not an error condition. Existing code should not treat it as an error, but as it has no concept of the sentinel value it will, and this will break existing behavior. If it was only the |
In that case, it seems like a new interface is the best option: func (x T) EmptyJSON() bool { return true } |
This proposal is a duplicate of a previously discussed proposal, as noted above, |
@rsc I see this as an alternative to the omitzero proposal. Instead of baking the omission policy into the struct tag, this proposal allows us to customize the policy on if we want to omit a field. It also lends itself towards the JSON-native "omission" notion instead of the go-specific "zero-value" or the go-json-specific notion of "empty-value". |
There are quite a number of "omit this field" proposals. #11939 proposes special-casing an |
@dsnet Yeah the |
When structuring json types, it would be very helpful to allow the custom types define if the value is to be omitted. This is similar to a javascript value may set to "undefined".
Just as we allow custom types to implement "MarshalJSON" to provide a custom value: ("null", multivariate, etc). So too should we allow these custom types to be set to "Omitted" as well.
This proposal may supersede other highly desired
omitnil
proposals as one may leverage this abstraction to accomplish the same goal.Proposal
Update
encoding/json
to check if a struct field implements anOmittable
interface whereOmittable
is defined as follows:If a fieldType implements this interface, omit the filed if the response of Omitted() is true.
Example (Omittable String)
Example (Omit-nil)
Compatibility
This may cause issues with existing custom types that happen to implement this new method. Though I would guess that the number of uses with such a pattern is low.
Implementations
I've implemented this locally and it seems to work fine. If approved I can submit a PR.
Related Proposals
The text was updated successfully, but these errors were encountered: