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: Go 2: obtain struct field name in type-safe way #36332

Closed
lifeng1992 opened this issue Dec 31, 2019 · 9 comments
Closed

proposal: Go 2: obtain struct field name in type-safe way #36332

lifeng1992 opened this issue Dec 31, 2019 · 9 comments
Labels
Milestone

Comments

@lifeng1992
Copy link

type Target struct {
    Name     string
    Path     string
    Date     time.Time
}

func main()  {
    ^Target{Name, Path} // equivalent []string{"Name", "Path"}
    ^Target{}.Name // equivalent "Name"
}

Good point

  • compatible with Go 1.x
  • just syntactic sugar
  • refactor friendly
  • avoid typo
@lifeng1992 lifeng1992 changed the title obtain field name in type-safe way proposal: obtain field name in type-safe way Dec 31, 2019
@gopherbot gopherbot added this to the Proposal milestone Dec 31, 2019
@lifeng1992 lifeng1992 changed the title proposal: obtain field name in type-safe way proposal: obtain struct field name in type-safe way Dec 31, 2019
@smasher164 smasher164 added v2 A language change or incompatible library change LanguageChange labels Dec 31, 2019
@ianlancetaylor ianlancetaylor changed the title proposal: obtain struct field name in type-safe way proposal: Go 2: obtain struct field name in type-safe way Dec 31, 2019
@ianlancetaylor
Copy link
Contributor

Can you give an example of where a program would use this?

In https://blog.golang.org/go2-here-we-come @griesemer lists three conditions for a language change:

  1. address an important issue for many people,
  2. have minimal impact on everybody else, and
  3. come with a clear and well-understood solution.

I'm not sure this is an important issue for many people.

@lifeng1992
Copy link
Author

lifeng1992 commented Dec 31, 2019

@ianlancetaylor

1. Update multiple attributes with struct, specified fields

type Target struct {
	ID    int    `valid:"-"`
	Name  string `valid:"alpha"`
	Sums  int    `valid:"-"`
	Email string `valid:"email"`
}

var tar = Target{
	ID:    1,
	Name:  "alice",
	Sums:  17,
	Email: "alice@gamil.com",
}

db.Model(&tar).UpdateColumns([]string{"sums", "email"})
// equivalent
db.Model(&tar).UpdateColumns(^Target{Sums, Email})

2. validate struct with specified fields

func handlerA(c *gin.Context)  {
	var tar Target
	if err := c.ShouldBindQuery(&tar); err != nil {
		panic(err)
	}
	validator.ValidateStruct(&tar, ^Target{Name})
	// ...
}

func handlerB(c *gin.Context)  {
	var tar Target
	if err := c.ShouldBindQuery(&tar); err != nil {
		panic(err)
	}
	validator.ValidateStruct(&tar, ^Target{Email})
	// ...
}

func handlerC(c *gin.Context)  {
	var tar Target
	if err := c.ShouldBindQuery(&tar); err != nil {
		panic(err)
	}
	validator.ValidateStruct(&tar, ^Target{Name, Email})
	// ...
}

@alanfo
Copy link

alanfo commented Dec 31, 2019

I gather from your examples that this proposal would be type-safe compared to what we do now because if the field names were mis-typed or were changed, then the compiler would be able to flag that immediately rather than leave it to a function to validate the names using reflection at runtime.

If so, it's a similar idea to C#'s nameof operator though that works for all kinds of entities, not just struct fields.

I think this is an interesting (and potentially valuable) idea but, if it were to be entertained for Go, I'd prefer to see something more akin to a nameof built-in function rather than a new ^ operator. This would be more indicative of what it is trying to achieve.

@ianlancetaylor
Copy link
Contributor

I feel like your examples leave out the most interesting part, which is the code that uses the field names. I guess that code must be written using the reflect package, and it must be looking up the fields by name or something like that. That code can already give an error if the name is incorrect, so I guess that this proposal is about moving an error from run time to compile time. Which I guess is what @alanfo said as well.

Personally I think that ^Target{} is an awfully cryptic way to achieve that goal. One consideration about Go is that people should be able to look at unfamiliar code and immediately understand what it does. It seems to me that a construct like ^Target{} would be very rarely used, and so people would not be familiar with what it means. I think we need a better argument to deploy such an unusual notation.

@beoran
Copy link

beoran commented Jan 7, 2020

While I agree the syntax proposed here is not very nice, a built in nameof() function, would be very useful for ORMs or for debugging. True, now we can do it using reflection, but as said, that's run time, not compile time, which nameof() could be.

Edit the semantic could be much like in this proposal. nameof(struct_value) returns an array with strings with the names of the exported fields of the struct value. nameof(struct_value.field) returns a single string with the name of the field.

@ianlancetaylor
Copy link
Contributor

This proposal permits compile-time type safety for struct field names, but that doesn't seem like a case that comes up very often. We can already do this; the only benefit here is compile-time type safety. This doesn't seem to "address an important issue for many people," as should be required for any language change.

As an aside, if we had this feature, one would expect it work for all types, not just struct types. I guess that would lead us more toward the nameof function that @beoran suggests.

Also, this proposal does not have strong support based on emoji voting.

For these reasons, this is a likely decline. Leaving open for four weeks for further comments.

@beoran
Copy link

beoran commented Jan 30, 2020

@ianlancetaylor Actually, struct field names do come up rather often in ORMs, where the struct's fields' names are often translated into names for the database columns. Now, we have to either use reflect, which is run time and has some performance issues, or maintain a manual or generated list of columns. For such cases, a built in nameof() built in function would be extremely useful. Should I open a separate issue for this idea?

@ianlancetaylor
Copy link
Contributor

@beoran Yes, I think nameof ought to be a separate proposal. It applies to a lot more than structs. It needs some explanation for how to handle unnamed values (nameof(0), nameof(f())).

@ianlancetaylor
Copy link
Contributor

No change in consensus, so closing.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants