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

reflect: Type.Name and Type.String expose "link name" mangling of type arguments #55924

Open
mdempsky opened this issue Sep 28, 2022 · 3 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@mdempsky
Copy link
Member

mdempsky commented Sep 28, 2022

The type parameters proposal (https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#reflection) states:

We do not propose to change the reflect package in any way. When a type or function is instantiated, all of the type parameters will become ordinary non-generic types. The String method of a reflect.Type value of an instantiated type will return the name with the type arguments in square brackets. For example, List[int].

It's ambiguous what "name" should be used. Also, whether only reflect.Type.String should have been affected, or reflect.Type.Name too.

cmd/compile generates two names for each type: a "link name" that corresponds to type identity (so the linker can deduplicate it against other identical types), and a "reflect name" that's simplified somewhat for user presentation via reflect APIs.

However, for instantiated types' reflect names, it currently uses the link names of the type arguments. For example: https://go.dev/play/p/JAP28idHc9z

Can/should we change this behavior?

Some noteworthy distinctions:

  • Reflect names use package name, whereas link names use package path. (reflect.Type.String says either is allowed though.)
  • Link names add "·N" suffixes to locally defined types to disambiguate them, whereas reflect names omit this.
  • Link names include package-path-qualifiers for non-exported struct fields and interface methods.
  • Link names include a = byte to identify embedded fields.

/cc @rsc @ianlancetaylor @griesemer @golang/compiler

@mdempsky mdempsky added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Sep 28, 2022
@mdempsky mdempsky added this to the Go1.20 milestone Sep 28, 2022
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Sep 28, 2022
@mdempsky
Copy link
Member Author

mdempsky commented Sep 28, 2022

Some noteworthy distinctions:

Another distinction: GOEXPERIMENT=unified supports defined types that are declared within type-parameterized functions, which implicitly parameterize the defined type.

The implicit type arguments are relevant to type identity, so they need to be included in the link name. But they're also currently included in the reflect name, for the same reason as above: https://go.dev/play/p/ORCQud4MPp6?v=gotip (The mangling used is T[implicits;explicits], where implicits and explicits are comma-separated type argument lists. If either list is empty, then the semicolon is omitted.)

I've thought it might be better/clearer if local types were given reflect names like Function.Type, so the above example would print main.F[int].T[string] instead of main.T[int;string]. (The link name would still need vargen disambiguation, because a function can have multiple identically-named defined types in separate blocks.)

@ianlancetaylor
Copy link
Contributor

ianlancetaylor commented Sep 29, 2022

My expectation was always that for a generic type T, instantiated with a type argument A, the reflect.Type.Name method would return T[A] or T[pkg2.A] and the reflect.Type.String method would return pkg.T[pkg2.A]. It clearly should not use the link name for type arguments. And I agree that for a local generic type (if such a thing is ever supported) the reflect name should be F[A1].T[A2].

@godcong
Copy link

godcong commented Nov 30, 2022

I think the function of reflect and go is a bit unrelated.

   strType := reflect.TypeOf(string("abc"))
   if strType == string { //do something... } //no way to compare this
   if strType.XxxType() == string { //do something... } // If we could compare this, a lot of functionality would be possible

For example, you can define the type in the key of the map:

   maps:=map[type]somevalue
   //get the value
   v:=maps[sometype]

There is also no need to use too much type conversion in the code

switch any(generic).type {
case xxx:
}

The current reflect doesn't do anything like this:

switch reflect.TypeOf(generic){
case //string or "string" what you can case???? What about if it's the type of a project on github?
}

With the current functionality, you can't do something with reflect that you should be able to do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
Status: In Progress
Development

No branches or pull requests

4 participants