Description
Problem
You can't use string var / const
in tags. Below is an illegal syntax -
type user struct {
name string `json:"` + FIELD_NAME + `"`
}
As @rsc told in this comment, I also feel tag syntax shouldn't be complicated.
However, this leads us to a situation where we need to carry a string
(tag) value everywhere in the code. I will try to explain with an example. Below code tries to update a user.Name
field in two different nosql databases. (However this issue remains valid in other scenarios too)
Suppose we have a user
struct as :-
type user struct {
ID string `bson:"ID" json:"ID"`
Name string `bson:"NAME" json:"NAME"`
}
Code to update the user.Name
in MongoDB will be like -
mongoFilter := map[string]string{"ID": "userID"}
mongoFieldVal := map[string]map[string]string{"$set": {"NAME": "new name"}}
userColl.UpdateOne(nil, mongoFilter, mongoFieldVal)
Code to update the user.Name
in ArangoDB will be like -
arangoFieldVal := map[string]string{"NAME": "new name"}
userColl.UpdateDocument(nil, "user_ID", arangoFieldVal)
As you can see the problem is -
- we need to carry the tag(json/bson) values
"ID"
and"NAME"
as string every-time we need to interact with these fields.
Problem(1)
- This increases the chances of doing mistakes because we need to type a string literal at different places.
Problem(2)
- Also its difficult to maintain because in case somebody updates the json tag value, one might miss to update the string(tag) value at few places, leading to creepy unnoticeable bug that escapes the build time check.
Solution Proposed
In my opinion, there should be single point to manage the field's tag value. Since adding string const inside field's tag value will complicate things, we can go the other way around.
We can have a tool to go:generate
the tag's value as string constant, and use these constants as the field's tag value.
- This reduces the need to type the string value while accessing the field and solves the Problem(1).
- In case somebody updates a field's name, the corresponding generated string constant will change, forcing the person doing the change to use the new string constant, at the build time itself. This solves the Problem(2).
Implementation
This is a very frequent usecase. So I feel, instead of using a third party code, there should be a support in the language tool itself.
If we eventually decide to implement this feature somewhere as a tool, there can be multiple ways to achieve this. At first, to start the discussion, a very raw idea is -
- Recommend using field tags for consistency.(We may want to ignore the const generation for the fields without tags)
- For every package, generate a
struct_field_tag_const_gen.go
file. This contains all structs'(in the current package) fields' tags as const string in the current package.
I have written a very raw code that generates a file with string constants for each package.
It uses ast.Inspect
and reflect.StructTag
api to access a struct's comments and its fields' tags.
It considers only those structs which have some magic comment on it. We can decide what mechanism to follow to filter out the structs. In case we decide this feature worth considering, I'll try to improve my current implementation.
/cc @rsc @alandonovan @mvdan