Skip to content

proposal: x/tools: support for struct field's tag as string const #40247

Closed
@amarjeetanandsingh

Description

@amarjeetanandsingh

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeProposalToolsThis label describes issues relating to any tools in the x/tools repository.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions