New type in generics

157 views
Skip to first unread message

Daniel Theophanes

unread,
Jan 13, 2024, 2:10:30 PM1/13/24
to golang-nuts
I have a situation where I would like to create a type, then set a property on it within a container. To set the type, I envisioned using a method "SetName" which would need to take a pointer receiver: (goplay share is down right now so I'll post inline:
type Namer interface {
SetName(name string)
}

I wish to create a new Namer type as well, ideally without using reflect. If I use [*Ob ] as the type parameter, that works, but then `new(T)` returns `**Ob`, which I can deference to get `*Ob`, but then the value is nil (Ob isn't created).

I'm working around this, but it surprised me, the interaction of a pointer receiver interface type constraint and then I can't create the desired type.

```
package main

import "fmt"

func main() {
ar := NewAppResult()
fmt.Printf("AR: %#v\n", *ar)
ar.Observation.Get("X1")
}

type Ob struct {
Gene  string
Value string
}

func (o *Ob) SetName(name string) {
// o is nil and this will panic.
o.Gene = name
}

type Namer interface {
SetName(name string)
}

type OrderedLookup[T Namer] struct {
List   []T
lookup map[string]T
}

func (ol *OrderedLookup[T]) Get(name string) T {
v, ok := ol.lookup[name]
if !ok {
var v T // T is a pointer, new(T) creates **Ob, but I cant use generic type of [Ob] because then Namer
v.SetName(name)
ol.lookup[name] = v
ol.List = append(ol.List, v)
}
return v
}

type AppResult struct {
Observation *OrderedLookup[*Ob]
}

func NewAppResult() *AppResult {
return &AppResult{
Observation: &OrderedLookup[*Ob]{},
}
}
```



Axel Wagner

unread,
Jan 13, 2024, 2:50:17 PM1/13/24
to Daniel Theophanes, golang-nuts
The way to do that is to add another level of indirection (as everything in Software Engineering):

type Namer[T any] interface {
    *T
    SetName(name string)
}
func WithName[T any, PT Namer[T]](name string) T {
    var v T
    PT(&v).SetName(name)
    return v
}

I will say, though, that it's not unlikely that you'll be happier if you don't do this and instead accept a plain interface value and let the caller allocate the value and pass in a pointer. But if you want to do it, this is the way.

--
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/8d0c816c-c332-4b44-87e3-9259ad173afcn%40googlegroups.com.

Daniel Theophanes

unread,
Jan 13, 2024, 3:26:57 PM1/13/24
to golang-nuts
Thank you. Yeah, that seems overly complicated. I can allocate interior to the generic object, but I can't use pointer-receiver methods, which is fine in my case, I'll just adjust the interior manually.

Thank you.
Reply all
Reply to author
Forward
0 new messages