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: Go 2: reflect.Type literals #27231

Closed
chmike opened this issue Aug 26, 2018 · 11 comments
Closed

reflect: Go 2: reflect.Type literals #27231

chmike opened this issue Aug 26, 2018 · 11 comments
Labels
FrozenDueToAge LanguageChange v2 A language change or incompatible library change
Milestone

Comments

@chmike
Copy link

chmike commented Aug 26, 2018

Currently, to get a reflect.Type value for a type T, one has to use the following expression

t := reflect.TypeOf((*T)(nil)).Elem()

It would be nice if we could have a lighter and more readable expression to get the reflect.Type value of a type. Maybe generics can help, if they are added to Go v2.

@cznic
Copy link
Contributor

cznic commented Aug 26, 2018

Not sure IIUC: https://play.golang.org/p/cCYeXm17cRl ?

@chmike
Copy link
Author

chmike commented Aug 26, 2018

It doesn't work for all types: https://play.golang.org/p/umwP9U8tsqn. The pattern I gave initially seam to work for all types.

@cznic
Copy link
Contributor

cznic commented Aug 26, 2018

Sure, but you do know in advance what type T is, don't you? Anyway, one can still do https://play.golang.org/p/NgMk4-6b2Og and it works for both scalar and non-scalar types.

@chmike
Copy link
Author

chmike commented Aug 26, 2018

Obviously, we can do that. But the goal is to get a reflect.Type value without having to declare a useless value.

We need to be able to write something like t := reflect.Type(int) or t := reflect.Type(anyType).

We need this when we want to pass the type value as argument to a function for instance. It is dumb to declare a variable we won't use just to get the type value. The expression I gave returns the type value without needing to declare a variable. It's just cumbersome to use and read.

@cznic
Copy link
Contributor

cznic commented Aug 26, 2018

Obviously, we can do that. But the goal is to get a reflect.Type value without having to declare a useless value.

The "useless" variable is used to achive your goal ;-)

We need to be able to write something like t := reflect.Type(int) or t := reflect.Type(anyType).

So far only some builtin functions can take a type as their first argument. Allowing that for user code in a package is a big language change. You'd need to make this proposal much more complete for such change to be even considered.

We need this when we want to pass the type value as argument to a function for instance. It is dumb to declare a variable we won't use just to get the type value.

If you pass - as you call it - a 'type value' to a function, the variable that you can directly pass to reflect.TypeOf is already declared - it's the parameter variable:

func f(x interface{}) reflect.Type { return reflect.TypeOf(x) }

edit: grammar

@chmike
Copy link
Author

chmike commented Aug 26, 2018

What I mean by "type value" is a value of type reflect.Type.

Currently I defined my function as func g(t reflect.Type). I currently expected that the user would have to write g(reflect.TypeOf((*T)(nil)).Elem()) which as you understand is pretty unreadable.

Your last suggestion is much more elegant. Here is an example: https://play.golang.org/p/jrqOUu5bZD4
It's not perfect, but it simplify the task for the user. If you allow me, I'll adopt it until it is fixed in Go2.

My goal was simply to report an issue to eventually clean up in Go2. I don't have a solution to suggest. As I said, I suspect the solution might be linked to the generic system where a function may be parameterized by a type.

@ianlancetaylor ianlancetaylor changed the title Cleanup proposal for Go v2: simplify the reflect.TypeOf((*T)(nil)).Elem() expression reflect: Go 2: simplify the reflect.TypeOf((*T)(nil)).Elem() expression Aug 26, 2018
@ianlancetaylor ianlancetaylor added LanguageChange v2 A language change or incompatible library change labels Aug 26, 2018
@ianlancetaylor ianlancetaylor added this to the Go2 milestone Aug 26, 2018
@ianlancetaylor
Copy link
Contributor

How often do these expressions occur in real code? Is it really worth changing the language for this?

@chmike
Copy link
Author

chmike commented Aug 26, 2018

My point would probably be more clear if the title was : 

reflect: Go 2: reflect.Type literals 

I can't say how often the reflect.TypeOf((*T)(nil)).Elem() pattern is used. I saw it documented as an idiomatic way to get a reflect.Type literal. It's been discussed here https://grokbase.com/t/gg/golang-nuts/153sxr7gqp/go-nuts-reflect-typeof-without-allocating-an-instance for instance. It comes up from time to time which implies that people do need such reflect.Type literals.

My goal was only to add a radar blip on this issue for the Go 2 developer team so they can fix it if it's easy. It might come for free with generics. Who can say now ?

A typical use case is when we need to build a map with Go types as keys and various kind of values, like an encoding function or specific actions for instance.

The actual different expressions to get the equivalent of a type literal are not simple and readable.

@chmike chmike changed the title reflect: Go 2: simplify the reflect.TypeOf((*T)(nil)).Elem() expression reflect: Go 2: reflect.Type literals Aug 27, 2018
@dsnet
Copy link
Member

dsnet commented Aug 29, 2018

The contracts proposal would provide a way to express this using type parameters (as @chmike hinted at above):

func TypeOf2(type T)() reflect.Type {
    return reflect.TypeOf((*T)(nil)).Elem()
}

With usage as:

t := reflect.TypeOf2(io.Reader)()

(Of course TypeOf2 is a terrible name)

@dsnet
Copy link
Member

dsnet commented Aug 29, 2018

How often do these expressions occur in real code?

It's fairly common to use this pattern since it is one of the few ways to get a reflect.Type for an interface type.

@ianlancetaylor
Copy link
Contributor

As @dsnet says, we should be able to write this function using generics. Let's go with that. We can reopen this if no generics proposal is adopted.

@golang golang locked and limited conversation to collaborators Oct 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

5 participants