generics question

280 views
Skip to first unread message

Jochen Voss

unread,
Apr 22, 2024, 5:25:09 PMApr 22
to golang-nuts
Using generics, can I somehow write a constraint which says that *T (instead of T) implements a certain interface?  The following code illustrated what I'm trying to do:

type A int

func (a *A) Set(x int) {
*a = A(x)
}

type B string

func (b *B) Set(x int) {
*b = B(strconv.Itoa(x))
}

type C1 struct {
Val []A
}

func (c *C1) Set(v int) {
for i := range c.Val {
c.Val[i].Set(v)
}
}

type C2 struct {
Val []B
}

func (c *C2) Set(v int) {
for i := range c.Val {
c.Val[i].Set(v)
}
}

I would like to use generics to use a single definition for the methods which here are func (c *C1) Set(v int) and func (c *C2) Set(v int).  (My real code has many base types, instead of just A and B.)  How can I do this?

I tried the naive approach:

type C[T interface{ Set(int) }] struct {
Val []T
}

but when I try to use the type C[A] now, I get the error message "A does not satisfy interface{Set(int)} (method Set has pointer receiver)".

Many thanks,
Jochen

Ian Lance Taylor

unread,
Apr 22, 2024, 8:55:12 PMApr 22
to Jochen Voss, golang-nuts
type C[P interface {
*E
Set(int)
}, E any] struct {
Val []P
}

Ian

Nagaev Boris

unread,
Apr 22, 2024, 10:36:25 PMApr 22
to Ian Lance Taylor, Jochen Voss, golang-nuts
I think it should be this (s/Val []P/Val []E/):

type C[P interface {
*E
Set(int)
}, E any] struct {
Val []E
}



--
Best regards,
Boris Nagaev

Jochen Voss

unread,
Apr 23, 2024, 2:00:40 AMApr 23
to golang-nuts
Thank you both!

This works, see my code below.  Followup question: is there a way to refer to the new type without having to list both the element type and the pointer type separately?  Below I have to write C[A, *A], which looks slightly ugly.  And in my real application something like Creator OrderedArray[ProperName] would look much more readable than Creator OrderedArray[ProperName, *ProperName] .

Many thanks,
Jochen

type Type interface{}

type Settable[E Type] interface {
*E
Set(int)
}

type C[E any, P Settable[E]] struct {
Val []E
}

func (c *C[E, P]) Set(v int) {

for i := range c.Val {
var ptr P = &(c.Val[i])
ptr.Set(v)
}
}

var c = C[A, *A]{Val: []A{1, 2, 3}}

Ian Lance Taylor

unread,
Apr 23, 2024, 1:35:03 PMApr 23
to Jochen Voss, golang-nuts
On Mon, Apr 22, 2024 at 11:01 PM Jochen Voss <joche...@gmail.com> wrote:
>
> This works, see my code below. Followup question: is there a way to refer to the new type without having to list both the element type and the pointer type separately?

Unfortunately there is not. At some point in the future the language
may support type inference for type arguments to types, for cases
where one type argument can be inferred from another type argument.
Currently that is not supported because there are some complex issues
involving cyclical types that need to be resolved or side-stepped.

In Go 1.23 I think it should be possible to simplify using these kinds
of types with a type alias as in "type X[E] = C[E, *E]".

Ian

Kevin Chowski

unread,
May 3, 2024, 1:02:37 PMMay 3
to golang-nuts
If you are just unhappy about the A and A* while using a literal for C: note that if you are willing/able to write a wrapper function instead of using a literal, type inference works well today:

func NewC[E any, P Settable[E]](val []E) C[E, P] {
return C[E, P]{Val: val}
}

var c = NewC([]A{1, 2, 3})

Kevin Chowski

unread,
May 3, 2024, 1:03:33 PMMay 3
to golang-nuts
Sorry for the noise - looks like you meant when passing around objects by this type, not just creating objects.
Reply all
Reply to author
Forward
0 new messages