-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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: add nameof() built-in function #36924
Comments
As I understand this, This is not quite what I was expecting, and it's interesting because, as you show, we can pretty much implement it using the reflect package. I think that even an individual field name could be returned if we provide two arguments: If that really does the job then it seems to me that we should start by writing this as a function, or set of functions, in the reflect package. Then if efficiency becomes a concern we can consider hoisting that function to become a compiler intrinsic, much as we've done with the sync/atomic and math/bits functions. |
@beoran - maybe you could elaborate why |
I use reflect for this kind of use case and cache/pre-compute the field names at init() time to avoid recalculations. Or use code generation if I really feel like it. |
This is very confusing. Opening this proposal I expected to see something akin to C#
And that would indeed be extremely useful. In C# I constantly use that feature for things like property binding, error messages, logging. In Go this would be useful to write ORM-like code where you often have to pass column names explicitly. That's very error prone. |
@ianlancetaylor, yes, the idea of nameof is that it returns type name information and field name about the arguments as a string or an array for strings. Maybe nameof is not the good name of this idea, but nameoftype or similar is a bit long. The name can be bike shedded later. I agree a second argument could be added that changes how nameof works. For struct values it is as you surmise, a nameof(&value) returns the name of the type of the value as a single string or an array of strings, I don't care much either way. And nameof(value) returns the names of the exported fields of the struct. As for your example nameof(&ci, &ci.Price) would then be "uint", while nameof(ci, ci.Price) would be "Price". If nameof really becomes built-in then nameof(&ci.Price) and nameof(ci.Price) could be also possible. As for non-struct values, I would propose to continue the scheme we are developing here: nameof(&something) returns the name of the type of something as a string, nameof(something) returns the name of either something itself, or for interfaces, the names of the interface's methods. So, type Bar int; const Foo = Bar(7)0 ; nameof(Foo) evaluates to "Foo" , and nameof(&Foo) evaluates to "Bar". And a := int64(7) ; nameof(a) evaluates to "a", and nameof(&a) evaluates to "int64". It's true that a part of the functionality of nameof could be implemented using reflection, and that could be a first step, basically as a utility function in "reflect". But, as a built-in function, it could also be used in situations where no value is produced normally, and, the result of nameof could be a compile time constant, probably if we allow arrays (not slices) to be constants as well. @ucirello, for ORM's the name of the type of a struct is most conveniently used when not prefixed by the package name, while %T prefixes the package name. Aslo %T doesn't allow getting the names of the exported fields of a struct value or type. @pierrec, I tend to use code generation most of the time, but that goes to show that it's somewhat of a missing feature in Go. @creker, I can see what you are getting at, perhaps the functionality I am thinking of is too confusing. I agree |
@beoran doesn't reflect already cover the "get the names of all fields in a struct"? From my experience, field names are not enough. You want to get both names and pointers to fields so that you can modify them. That's how some ORM-like libraries work. |
@crecker, yes, considering it, my proposal is mxing up two things, although these came from the original proposal, namely getting the names of a struct's fields, which could probably be something like reflect.FieldNameOf(), and nameof() which should be closer to C#'s #nameof. I could change this proposal and start with C#'s definition, adapted from here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof nameof built-in functionThe nameof built-in function obtains the name of a variable, type, or member fmt.Println(nameof(shopping.CartItem)) // output: CartItem
fmt.Println(nameof(int)) // output: int
fmt.Println(nameof(shopping.CartItem.Price)) // output: Price
var numbers = []int{ 1, 2, 3 };
fmt.Println(nameof(numbers)); // output: numbers
fmt.Println(nameof(len(numbers))) // output: len
fmt.Println(nameof()) // output: (the empty string) As the preceding example shows, in the case of a type and a package, the The nameof built-in function is evaluated at compile time and has no effect You can use the nameof built-in function or ORM, for debugging, or to make type Named {
Name *string
}
func (n *Named) SetName(name *string) error {
if name == nil {
return fmt.Errorf(nameof(name) + " cannot be nil" )
}
n.Name = name
} |
Wouldn't |
@jimmyfrasche , If we follow the design of the C# nameof, then yes, since the compiler doesn't know at compile time how the function will be called and what the name of the parameter will be. |
Should we close this proposal and open a new one that is more like C# As noted above, it seems to me that this proposal can already be implemented using the reflect package. |
You're right, therefore I withdraw this proposal and open another for the C#-like nameof in the linked issue. |
I am experienced, I have been using Go for 10 years since before v1.0.
Batch files, Basic, C, C++, D, Java, Javascript, Lua, Objective-C, Oberon, Pascal, PHP, Python, R, Ruby, Shell scripts, Visual Basic, ...
It would not make Go easier to learn, but also not substantially harder. If the new built-in function is well documented, everyone who doesn't know it yet can read its documentation to find out how it works.
This idea is based on the proposal proposal: Go 2: obtain struct field name in type-safe way #36332.
In stead of special syntax I proposed a built-in function, which is more Go-like and easier to learn.
This proposal would help people writing ORM's, interpreters, or with debugging aid, and other people who need to use the names of Go language artifacts, such as struct field names, or type names have to be used as strings.
Yes, adding a new built in function is normally completely backwards compatible, and does not break the Go1 compatibility guarantee.
Example: Orm-ish use.
https://play.golang.org/p/ZhE2LgD9vLs
The function has to be implemented, documented and tested.
None, unless if we need some vet checks for abuse of nameof().
Low, because only if the function is used, the compiler has at do a few type lookups, but it should already have that data available.
None, the whole point is to have this functionality at compile time.
See above for a partial run time simulation. More details need to be worked out for non-struct uses.
The Built-in_functions section would need to get a sub chapter on "Obtaining Names" or such.
It somewhat overlaps with reflect, but nameof() could also fetch names of non-expressions, which is not possible using reflect.
Not directly, but it could be expected, since it wold lessen the need for using reflection.
Some minor perfomance increase for the use cases of nameof().
Comparing a simulated nameof() based on reflection whith a compiler based built-in function
No.
No.
As for how to deal with expressions that really have no names themselves, like nameof(0), nameof(f()) ofr f() Foo, in these cases, I propose nameof() would return the names of the types of the expression, so this is "int" and "Foo", respectively. In fact every for every non-constant expression the name is that of the type or fields of the type. For const and types, the name of the const or the type is returned.
The text was updated successfully, but these errors were encountered: