-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
encoding/json: tag json:"-"
doesn't hide an embedded field
#35501
Comments
Hmm. While I agree that intuitively this is what one would expect, I don't think the docs give a definitive answer. The pieces of the docs that explain |
Here's another tricky question. The docs say:
However, does this mean just the original Go field's name, or does it also include the JSON field name one can add via a struct field tag? Right now, the "shadowing" of field names follows what's in the struct tags. That is, your |
Well, |
Here's an example of my reasoning above: https://play.golang.org/p/lEDqVGEVxAR The shadowing happens based on what's in the struct field tags. If we completely swap that and use the original struct names instead, we'd break valid use cases like this one.
You're right there. But even if you say "in that case the name remains the original |
I'll leave this open for a week if anyone has more thoughts, or a specific way in which this could be changed without breaking existing valid use cases. The only idea that comes to mind that would be truly backwards-compatible would be to extend the json tag syntax to allow omitting a field name, not just a specific field only. For example, The question then would be if it's worth adding this feature. How often does one want to omit fields from anonymous structs? Are there any current workarounds? Do any external json libraries support this feature? |
If the behaviour isn't changed, can it at least be documented better, so
that |
Yes, whatever we decide to do, I think it would be good to clarify that the visibility rules apply to the JSON names alone. |
I looked into this issue myself and I feel like the observation of @ainar-g is valid. In the documentation of encoding/json the section explaining
Now, if we extend the examples provided above (by @ainar-g and @mvdan) with the Therefore I would argue, that if the "omitting" for |
Thanks @breml. I agree that this is intuitively what one would understand; it was my first impression too. You also raise a good point about how For the record, I still think this would be nice to have, for the sake of consistency. Unfortunately, while For example, taking the original example once again:
Following the Aside from turning I assume this is what you meant by your sentence below:
It's certainly worth a try, and it could work, but I still wonder if it would break any existing valid uses of |
Change https://golang.org/cl/211457 mentions this issue: |
@ainar-g @breml please give the CL above a look, or give it a try with your programs. When I wrote it in December, I'm pretty sure the examples from this thread were fixed. I've just rebased it. I still think this is a bit risky, so I don't want to merge it for 1.15 during the freeze. However, any help testing or reviewing the change is very much welcome, so that we can look at merging once the tree reopens in eleven weeks. |
@mvdan Sorry, I couldn't check the patch earlier. I can confirm that
the patch does make the encoder shadow the embedded field. I've skimmed
through the patch and left a small stylistic comment with
a |
Stepping back a bit, what's the original use-case that inspired this issue? Is it the desire to be able to embed some other struct type, but exclude certain fields from being forwarded? |
@dsnet, that was a long time ago, but I think that that was indeed the original intent, yes. |
It sounds like a feature to exclude certain fields from some other struct is what's really desired and we're really getting in the weeds of the name conflict resolution logic to hack up something that could be used for that purpose. After all, declaring a new field with the hopes that it cancels out some other field really feels like a hack. |
That's kind of what the discussion came to the first time I filed this issue. See this comment by me and this comment by @mvdan. I don't really have the need to exclude fields with hacks currently, since I don't work on that original project any more, but having the behaviour defined, documented, and checked would still be nice. |
I agree we should improve the documentation, but I personally think the current behavior is correct. It seems like the best way to describe the behavior is that 1) we ignore all unexported fields and fields with an explicit |
That sound fine to me too. I'm happy to abandon my CL in favor of a documentation CL. |
@mvdan honestly I'm in favor of your CL, so many times I had to create an identical struct with just the missing field or use reflect / map. |
What does this mean? Can you elaborate on what you're trying to do? What I described in #35501 (comment) is high-level description of what currently happens. We should think of the name collision logic in terms of the JSON object name, not the Go struct field name. CL/211457 bakes in more information about the original Go struct field name into the name conflict resolution logic (as implemented by the |
My understanding of the CL was that it'd allow: type A struct {
Name string `json:"name"`
}
type B struct {
A
Name string `json:"-"`
} To work (as in return Right now the only real way to omit a field is to either empty it, marshal, put back the old value, or create a whole new struct without that field and copy all the other data to it. |
This sounds like the use-case I mentioned earlier #35501 (comment). Trying to adjust the name conflict rules to make this work is a hack. The existence of a principled way to exclude fields is 1) more clear as it expresses what the author wants and 2) is simpler since it doesn't requiring modifying the existing naming rules to be more complicated. |
Also, that's not quite true. Using the rules that already exist today, you can do:
|
I'm have been programming in Go as my main language for over 7 years and you just blew my mind. |
@dsnet, amazing trick, thanks! Although
|
That sounds like a vet bug; it should really only complain about duplicate tag names living directly in the same struct. |
@mvdan My intuition is that users should get a warning in the My hunch is that the number of users that have this happen to them accidentally >> the number of users that do this intentionally. (This is "mind blowing" after all.) I am also more worried about not reporting the accident case than I am about annoying the exclude case. (But my hunches and priorities could be all wrong here.) It is definitely possible to have an annotation that vet parses to understand the intent and suppress the warning for the intentional exclude. The annotation could be something like a funny field or struct name so it would not be too intrusive. It could also be an end of line comment or a field tag. Not sure the extra complexity is warranted though. |
Another (more intuitive) way to omit attributes from json marshalling is: type A struct {
Name string `json:"name"`
Value string `json:"value"`
}
type B struct {
A // Or *A, both possible
Name *struct{} `json:"name,omitempty"` // This attribute will be omitted
}
// And marshal something of type B See https://play.golang.org/p/0OdxDtXcx8-, see also this old blog post. |
It's work for me to omit attributes from json marshalling: type B struct { |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes, see
gotip
version.What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
https://play.golang.org/p/uKY3umGYEp3
What did you expect to see?
Either:
Or:
What did you see instead?
The text was updated successfully, but these errors were encountered: