Skip to content
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: reflect: allow multi-line struct tags #42182

Closed
gtrevg opened this issue Oct 24, 2020 · 4 comments
Closed

proposal: reflect: allow multi-line struct tags #42182

gtrevg opened this issue Oct 24, 2020 · 4 comments

Comments

@gtrevg
Copy link

gtrevg commented Oct 24, 2020

Overview

Go's struct tags has been wildly successful. It has been so successful, in fact, that many projects leverage the reflect.StructTag system to support code generation, struct value validation, storage and retrieval, UI presentation, and a number of other use cases. Tagging allows one structure to be used throughout the layers of the program resulting in having a central location to modify the attributes, yet also allowing customizations to be applied to each of the layers.

The following example is a use case where the struct is used to:

  • Generate a presentation layer (label, description)
  • Generate REST API docs (label, description, json, example, pattern)
  • Deserialize and validate data coming into a REST API (json, pattern)
  • Define how to persist the data in a SQL database (sql)
  • Serialize a response back to the client (json)

All of that meta information together could easily be as complicated as the following:

type Machine struct {
    ID string `json:"id" yaml:"id" description:"UUID auto-generated to identify the machine" pattern:"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" sql:"type:varchar(36);not null;unique;primary_key" label:"Machine Id" example="1328149e-15a1-11eb-adc1-0242ac120002"`

    Host string `json:"host,omitempty" yaml:"host,omitempty" pattern:"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])" description:"Host name for the machine" label:"Host Name" example:"myserver.domain.com" sql:"type:varchar(255)"`

    IPv4 string `json:"ipv4,omitempty" yaml:"ipv4,omitempty" pattern:"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}" description:"IPv4 address for the machine." label:"IPv4 Address" example:"127.0.0.1" sql:"type:varchar(15)"`
}

Proposal

To improve readability, reduce mistakes, and allow the meta information to continue to scale, a minor backwards compatible change could be applied to the struct tag spec: allow newlines and tabs to exist within the tag. This would enable the following struct definition:

type Machine struct {
    ID string `
        label:"Machine ID"
        description:"UUID auto-generated to identify the machine"
        json:"id"
        yaml:"id"
        pattern:"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
        example="1328149e-15a1-11eb-adc1-0242ac120002"
        sql:"type:varchar(36);not null;unique;primary_key"
    `

    Host string `
        label:"Host Name"
        description:"Host name for the machine"
        json:"host,omitempty"
        yaml:"host,omitempty"
        pattern:"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])"
        sql:"type:varchar(255)"
    `

    IPv4 string `
        label:"IPv4 Address"
        description:"IPv4 address for the machine"
        json:"ipv4,omitempty"
        yaml:"ipv4,omitempty"
        pattern:"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}"
        sql:"type:varchar(15)"
    `
}

The resulting structure is much more readable and can help prevent mistakes (ironically, just converting the above example into the more readable format exposed my own mistake of missing an end quote). This allowance would still be backwards compatible with all previous tag definitions. In addition, denoting multi-line content with `` is already a well understood and widely used pattern in the Go community. This would be a natural fit that some probably already expect to work.

These new characters should only be allowed in the spaces between the key:"value" pairs. This would be consistent with the documentation on StructTag:

https://golang.org/src/reflect/type.go?s=30914:30935#L1101

// A StructTag is the tag string in a struct field.
//
// By convention, tag strings are a concatenation of
// optionally space-separated key:"value" pairs.
// Each key is a non-empty string consisting of non-control
// characters other than space (U+0020 ' '), quote (U+0022 '"'),
// and colon (U+003A ':'). Each value is quoted using U+0022 '"'
// characters and Go string literal syntax.

Dependencies

  • The Go formatter would need to enforce a style for multi-line tags

Related:

@gopherbot gopherbot added this to the Proposal milestone Oct 24, 2020
@ianlancetaylor ianlancetaylor changed the title proposal: reflect struct tags: allow multi-line tags proposal: reflect: allow multi-line struct tags Oct 24, 2020
@ianlancetaylor
Copy link
Contributor

See also #15893, #38641 and #40247.

I think this may be a dup of #38641.

@gtrevg
Copy link
Author

gtrevg commented Oct 24, 2020

@ianlancetaylor Yes, it does look like a dup of #38641 (which seems also to have gone through some evolutions & discussions and was eventually closed).

@beoran
Copy link

beoran commented Oct 26, 2020

I think that seeing the recurrence and popularity of these, improved struct tags would be a popular improvement to Go language, even though it is not clear exactly how this could be done. Perhaps a meta-issue would be useful?

@rsc
Copy link
Contributor

rsc commented Oct 28, 2020

Closing as duplicate of #38641.
(That was only a few months ago, not much about Go has changed since then.)

@rsc rsc closed this as completed Oct 28, 2020
@golang golang locked and limited conversation to collaborators Oct 28, 2021
@rsc rsc moved this to Declined in Proposals Aug 10, 2022
@rsc rsc added this to Proposals Aug 10, 2022
@rsc rsc removed this from Proposals Oct 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants