Generic pointer field comparable with single type parameter possible?

105 views
Skip to first unread message

Ed Pelc

unread,
Feb 1, 2022, 11:29:05 PM2/1/22
to golang-nuts
Hello,

I'm trying out the go1.18beta2 by attempting to move from codegen based generics using a custom tool to 1.18's type parameters. I looked extensively for examples and others trying to do something similar but found little. I figured out a working way to do this but it seems extensive.

I'm trying to have a generic field on a struct(UpdateModelRequest) which is a *T so that the struct can be read from json and then processed. A few methods or fields need to be exposed so that you can interact with the generic field from UpdateModelRequest's methods. I also need to be able to check if this generic field is left nil.

I was able to get this to work but I'm curious if it could be simplified at all as it seems complicated to require two type parameters for this. I figured this out after trying to follow the `pointer method` section from the generics proposal. It seems to be written for a slightly different use case though.

Working, but complicated(requires two type params): https://gotipplay.golang.org/p/iz2GKYtaL-A

Basically I do not understand why you can't do a simpler single type parameter version using comparable directly within DataRecord. I know the spec says comparable cannot be used as a variable, or value(and I presume this means a struct field too) but it works with the two type parameter redirection above. I'd like to know why the two parameter version works for some reason.

Single type parameter version: https://gotipplay.golang.org/p/UO8e6zQwi0k


My research/help others find this. I could not find much for people trying to do something similar even though it seems a common use case(we have many different data types that need basic crud http handlers):

From reading the 1.18 spec it says you can't embed `comparable` types as a variable or value. I assume this means you also can't use as a struct field. I'm not sure why you can't do this or if it's just a limitation for now. Are you expected to add an `IsNil() bool` method as a replacement for this?

From the spec re comparable type parameter(Record field in example) as a struct field:

"They cannot be the types of values or variables, or components of other, non-interface types."

If you try to use a pointer field(line 12) to make the record comparable then you get this error.

"req.Record.SetID undefined (type *Record is pointer to type parameter, not type parameter)"

Ed Pelc

unread,
Feb 1, 2022, 11:32:09 PM2/1/22
to golang-nuts
**please use this as single type parameter version instead: https://gotipplay.golang.org/p/ZrOqCj1R_va

Axel Wagner

unread,
Feb 2, 2022, 1:13:38 AM2/2/22
to Ed Pelc, golang-nuts
On Wed, Feb 2, 2022 at 5:29 AM Ed Pelc <edro...@gmail.com> wrote:
I was able to get this to work but I'm curious if it could be simplified at all as it seems complicated to require two type parameters for this. I figured this out after trying to follow the `pointer method` section from the generics proposal. It seems to be written for a slightly different use case though.

Working, but complicated(requires two type params): https://gotipplay.golang.org/p/iz2GKYtaL-A

This seems to be what you are supposed to do, yes. Note that the caller doesn't need to really concern themselves with the second type-parameter. It's virtual, in a sense.

Basically I do not understand why you can't do a simpler single type parameter version using comparable directly within DataRecord. I know the spec says comparable cannot be used as a variable, or value(and I presume this means a struct field too) but it works with the two type parameter redirection above. I'd like to know why the two parameter version works for some reason.

Single type parameter version: https://gotipplay.golang.org/p/UO8e6zQwi0k

The compiler tells you why this doesn't work: You are comparing to `nil` and not all values can be compared to `nil`. For that, you need the type argument to be a pointer specifically. Telling the compiler that it is a pointer, is what the second type parameter is for.

You can do this, if you want to: https://gotipplay.golang.org/p/aDGzOF7EWIF

But, of course, this means that your type might be instantiated with a non-pointer and it's no longer possible to distinguish between "the zero value" and "not given".
 
My research/help others find this. I could not find much for people trying to do something similar even though it seems a common use case(we have many different data types that need basic crud http handlers):

From reading the 1.18 spec it says you can't embed `comparable` types as a variable or value. I assume this means you also can't use as a struct field. I'm not sure why you can't do this or if it's just a limitation for now. Are you expected to add an `IsNil() bool` method as a replacement for this?

From the spec re comparable type parameter(Record field in example) as a struct field:

"They cannot be the types of values or variables, or components of other, non-interface types."

If you try to use a pointer field(line 12) to make the record comparable then you get this error.

"req.Record.SetID undefined (type *Record is pointer to type parameter, not type parameter)"

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4b4ce168-64fd-4534-9925-989b1371a32bn%40googlegroups.com.

Ed Pelc

unread,
Feb 2, 2022, 11:50:12 AM2/2/22
to golang-nuts
Thanks for the third demo and info!

I hope they add a way to do this without a second parameter and still be able to check for nil. Seems odd that you can't since pointers are so common this would seem a common use case.

Also I'm still not sure why you can pass in comparable via two parameters and use as a struct field but doing so with a single field isn't allowed. I get in the spec it says it isn't allowed to be a value/variable but why would this not carry over to the two type parameter example? I'm happy it doesn't as it makes my example work but I'm not sure why the compiler doesn't catch this or how it interprets it.
Reply all
Reply to author
Forward
0 new messages