[generics] type constraint for structs

3,768 views
Skip to first unread message

Pee Jai

unread,
Jun 22, 2020, 10:08:05 PM6/22/20
to golang-nuts
I can't find a way to constrain for just structs. I don't want primitives.

Ian Lance Taylor

unread,
Jun 23, 2020, 8:34:40 PM6/23/20
to Pee Jai, golang-nuts
On Mon, Jun 22, 2020 at 7:08 PM Pee Jai <p...@pjebs.com.au> wrote:
>
> I can't find a way to constrain for just structs. I don't want primitives.

The design draft doesn't provide any mechanism for a type constraint
to match any arbitrary struct type, and not any other kind of type.

But it's not clear why that would be useful. The only things you can
do with a value of an arbitrary struct type are things that you can do
with a value of any arbitrary type.

Ian

Pee Jai

unread,
Jun 24, 2020, 9:28:58 AM6/24/20
to golang-nuts
Here is my use case: https://godoc.org/github.com/rocketlaunchr/react#UnmarshalState

That function has an argument that accepts only a struct. I use the reflect package to iterate over the structs fields (and also to check if it actually is a struct). The function has notapplicability for non-structs.

Currently I have to notify the user via documentation that only a struct is allowed since the type is officially an `interface{}`. This is very crude.

If there was a way to add a type constraint for only structs, then I don't need to use documentation, notwithstanding the use of reflect package to iterate over the struct fields.

Robert Engels

unread,
Jun 24, 2020, 9:34:41 AM6/24/20
to Pee Jai, golang-nuts
Generics will not solve this fully anyway - you’ll still need reflection. Why not just return empty if the user doesn’t pass a struct?

On Jun 24, 2020, at 8:29 AM, Pee Jai <p...@pjebs.com.au> wrote:


--
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/e86e677b-784d-47c5-b8b9-aedc37977ba5o%40googlegroups.com.

David Finkel

unread,
Jun 24, 2020, 3:22:27 PM6/24/20
to Robert Engels, Pee Jai, golang-nuts
On Wed, Jun 24, 2020 at 9:34 AM Robert Engels <ren...@ix.netcom.com> wrote:
Generics will not solve this fully anyway - you’ll still need reflection. Why not just return empty if the user doesn’t pass a struct?

That sounds like a bug waiting to happen.

I have a library with a similar reflection-related use-case involving reflection, which currently panics when it gets a non-struct-type. It would be nice to have compile-time type-checking, if possible.

Ian Lance Taylor

unread,
Jun 24, 2020, 6:18:13 PM6/24/20
to David Finkel, Robert Engels, Pee Jai, golang-nuts
On Wed, Jun 24, 2020 at 12:22 PM David Finkel <david....@gmail.com> wrote:
>
> On Wed, Jun 24, 2020 at 9:34 AM Robert Engels <ren...@ix.netcom.com> wrote:
>>
>> Generics will not solve this fully anyway - you’ll still need reflection. Why not just return empty if the user doesn’t pass a struct?
>>
> That sounds like a bug waiting to happen.
>
> I have a library with a similar reflection-related use-case involving reflection, which currently panics when it gets a non-struct-type. It would be nice to have compile-time type-checking, if possible.


Generics don't solve all problems. I'm inclined to say that this is a
problem that they don't solve. Sorry.

Ian
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CANrC0BgyoPvEWJEOOrJwt-3qfLvSxc6CX9yLoYBPxYZV8GBZLg%40mail.gmail.com.

Pee Jai

unread,
Jun 24, 2020, 7:34:35 PM6/24/20
to golang-nuts
I disagree. A type constraint for a struct would definitely provide compile-time guarantee that only a struct can be used. 

On Thursday, June 25, 2020 at 8:18:13 AM UTC+10, Ian Lance Taylor wrote:
On Wed, Jun 24, 2020 at 12:22 PM David Finkel <david...@gmail.com> wrote:
>
> On Wed, Jun 24, 2020 at 9:34 AM Robert Engels <ren...@ix.netcom.com> wrote:
>>
>> Generics will not solve this fully anyway - you’ll still need reflection. Why not just return empty if the user doesn’t pass a struct?
>>
> That sounds like a bug waiting to happen.
>
> I have a library with a similar reflection-related use-case involving reflection, which currently panics when it gets a non-struct-type. It would be nice to have compile-time type-checking, if possible.


Generics don't solve all problems.  I'm inclined to say that this is a
problem that they don't solve.  Sorry.

Ian




>> On Jun 24, 2020, at 8:29 AM, Pee Jai <p...@pjebs.com.au> wrote:
>>
>> 
>> Here is my use case: https://godoc.org/github.com/rocketlaunchr/react#UnmarshalState
>>
>> That function has an argument that accepts only a struct. I use the reflect package to iterate over the structs fields (and also to check if it actually is a struct). The function has notapplicability for non-structs.
>>
>> Currently I have to notify the user via documentation that only a struct is allowed since the type is officially an `interface{}`. This is very crude.
>>
>> If there was a way to add a type constraint for only structs, then I don't need to use documentation, notwithstanding the use of reflect package to iterate over the struct fields.
>>
>> On Wednesday, June 24, 2020 at 10:34:40 AM UTC+10, Ian Lance Taylor wrote:
>>>
>>> On Mon, Jun 22, 2020 at 7:08 PM Pee Jai <p...@pjebs.com.au> wrote:
>>> >
>>> > I can't find a way to constrain for just structs. I don't want primitives.
>>>
>>> The design draft doesn't provide any mechanism for a type constraint
>>> to match any arbitrary struct type, and not any other kind of type.
>>>
>>> But it's not clear why that would be useful.  The only things you can
>>> do with a value of an arbitrary struct type are things that you can do
>>> with a value of any arbitrary type.
>>>
>>> Ian
>>
>> --
>> 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 golan...@googlegroups.com.
>> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/e86e677b-784d-47c5-b8b9-aedc37977ba5o%40googlegroups.com.
>>
>> --
>> 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 golan...@googlegroups.com.
>> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/8013EEB8-78E6-455D-B846-8A826682B879%40ix.netcom.com.
>
> --
> 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 golan...@googlegroups.com.

Pee Jai

unread,
Jun 24, 2020, 7:57:13 PM6/24/20
to golang-nuts
Just to clarify: This is not directly related to generics. It is related to interfaces (and the type constraints feature) which are incidental to generics and provides extra power to developers. In this particular use case, it provides a useful compile-time check for an argument that is intended to be a generic struct.

Ian Lance Taylor

unread,
Jun 24, 2020, 8:03:13 PM6/24/20
to Pee Jai, golang-nuts
On Wed, Jun 24, 2020 at 4:57 PM Pee Jai <p...@pjebs.com.au> wrote:
>
> Just to clarify: This is not directly related to generics. It is related to interfaces (and the type constraints feature) which are incidental to generics and provides extra power to developers. In this particular use case, it provides a useful compile-time check for an argument that is intended to be a generic struct.

Agreed.

Just to be clear, we don't add things to Go just because they are
useful. Every language feature that someone suggests is useful, or
they wouldn't suggest it. Adding a new specific type constraint
meaning "type must be a struct" has a cost: it has to be documented,
explained, tested, maintained. If we want to add it to the language,
it needs to bring a benefit that outweighs that cost.

Of course this discussion is premature in any case since generics, and
type constraints, are not yet a part of the language.

Ian
> 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/2f8db812-077d-4955-a2ec-78657af1ec45o%40googlegroups.com.

Robert Engels

unread,
Jun 24, 2020, 8:03:51 PM6/24/20
to Pee Jai, golang-nuts
But if you interpret the method as ‘format this struct’ a struct has named fields. A primitive has no named fields so the output is empty. 

It is almost always easier to define the contract if the method in an unbreakable way than rely on the compiler to catch all problems. 

For example what do you get if you pass an empty struct ?

On Jun 24, 2020, at 6:34 PM, Pee Jai <p...@pjebs.com.au> wrote:


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/b15a841e-46bd-450f-8c71-d4429700b050o%40googlegroups.com.

Jeremy Kassis

unread,
May 18, 2022, 10:36:26 PM5/18/22
to golang-nuts
Where exactly did this land? Seems like an important conversation...

```
// RPCHandler passes RPCReq and RPCRes as fn args
func RPCHandler[T RPCReq, S RPCRes](fn func(T, S)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        req := T{}
        if err := reqBodyReadAll(w, r, &req); err != nil {
            resWriteErr(w, err)
            return
        }
        res := S{}
        fn(req, res)
        resWriteAll(w, r, res)
    }
}
```

Ian Lance Taylor

unread,
May 18, 2022, 10:41:29 PM5/18/22
to Jeremy Kassis, golang-nuts
On Wed, May 18, 2022 at 7:36 PM Jeremy Kassis <jka...@gmail.com> wrote:
>
> Where exactly did this land? Seems like an important conversation...

To date there is no way to write a constraint that requires that a
type argument be a struct type.


> ```
> // RPCHandler passes RPCReq and RPCRes as fn args
> func RPCHandler[T RPCReq, S RPCRes](fn func(T, S)) http.HandlerFunc {
> return func(w http.ResponseWriter, r *http.Request) {
> req := T{}
> if err := reqBodyReadAll(w, r, &req); err != nil {
> resWriteErr(w, err)
> return
> }
> res := S{}
> fn(req, res)
> resWriteAll(w, r, res)
> }
> }
> ```

I would write simply "var req T" and "var res S".

Ian

Abraham

unread,
Sep 14, 2022, 10:48:19 AM9/14/22
to golang-nuts
I am glad I found this thread because I was just now breaking my head figuring out why my <struct constraint> was not working....

Makis Maropoulos

unread,
Mar 27, 2024, 8:28:19 PM (24 hours ago) Mar 27
to golang-nuts
Same here @Abraham, 

    ResponseType interface {
        ~struct{}
    }

Obviously this doesn't work, I would love to see it working though.
Reply all
Reply to author
Forward
0 new messages