Code generation is the only option I can think of, perhaps with a top-level generic function to dispatch to the correct instance: https://go.dev/play/p/9nCZQsfOeyx
Unfortunately the compiler doesn't accept this: func HelperFn[T interface{ *lib1.Baz | *lib2.Baz }](baz T) int { return baz.GetBar().GetFoo().Get() } On Wednesday, 7 December 2022 at 18:51:19 UTC dple...@google.com wrote: > On Wed, Dec 7, 2022 at 4:39 AM Brian Candler <b.ca...@pobox.com> wrote: > >> On Tuesday, 6 December 2022 at 21:05:48 UTC dple...@google.com wrote: >> >>> I am trying to figure out if there's a good way to build a helper that >>> can be used against different sets of nested types that have a common >>> structure. >>> >>> So, for example, say there are two libraries, `lib1` and `lib2` and both >>> define types Foo, Bar, and Baz with: >>> >>> type Foo struct { ... } >>> type Bar struct { ... } >>> func (b *Bar) GetFoo() *Foo { ... } >>> type Baz struct { ... } >>> func (b *Baz) GetBar() *Bar { ... } >>> >>> But `lib1` and `lib2` both define different additional methods on some >>> of these structs, so I can't just merge them into a single library. >>> >> >> It seems to me that lib1.{Foo,Bar,Baz} and lib2.{Foo,Bar,Baz} are >> completely different types. They just happen to have similar names. >> >> Hence I ask, what's the commonality that you're trying to expose? If >> it's that both lib1.Baz and lib2.Baz have a GetBar() method, then that >> sounds like an interface - except if one returns a lib1.Bar and the other >> returns a lib2.Bar, then they are not the same interface at all, so you're >> back to "these are completely different types". Is there something common >> in Foo ? >> > <snip> > > Why not just have HelperFn1(lib1.Baz) and HelperFn2(lib2.Baz)? >> > > My actual use case involves a code generator, where lib1 and lib2 (and > possibly dozens of additional libraries) are all outputs of the same > generator with slightly different arguments, generated by various different > teams and therefore entirely outside of my control. > > The generator in question reads a schema file and outputs a library of Go > structs for all the data types defined by the schema. There are more than a > thousand such data types; they have getters and setters for their > attributes, and they're all nested in a giant tree, so e.g. code could call > > root := &lib1.Root{} > root.GetFoo().GetBar().GetBaz().GetQux().GetFleem().SetName("hello") > > The problem is that various users of the code generator have their own > schemas, which are generally made by taking a common standard schema and > adding extra fields needed by whatever specific project the users are > working on. So for example one project might add a .GetSpoo() method to the > Foo type, while another adds GetAlias to Fleem, etc. > > What I really want to do is be able to write a helper like: > > package examplehelper > > func SetFleemName(root ???, name string) { > root.GetFoo().GetBar().GetBaz().GetQux().GetFleem().SetName(name) > } > > such that any project can have its own generated library and can call > `examplehelper.SetFleemName(root, "foo")` on a Root{} from their own > generated library, as long as the Root has GetFoo(), the Foo has GetBar(), > etc. down to the Fleem having a SetName(string). > > This is technically possible with generics, but not practical, because it > requires writing e.g.: > > x := lib1.Root{} > helper.SetFleemName[*lib1.Fleem, *lib1.Qux, *lib1.Baz, *lib1.Bar, > *lib1.Foo](x, "foo") > > and in my real use case that list of type parameters would have more than > a thousand types in it. > > Right now I'm experimenting with whether it's reasonable to use code > generation to solve this - a code generator could either just copy a helper > library and replace all the imports with a specific generated library, or > could build a generated-library-specific "bridge" library that defines a > bunch of > > var SetFleemName = generichelper.SetFleemName[*lib1.Fleem, *lib1.Qux, > ...<a thousand more types>] > > But there's a lot of overhead to having everything go through a generator, > and it makes the code harder to read, harder to debug, and harder to use in > IDEs. I am hoping that there's some Golang feature I'm just not aware of > that would allow me to do this in the language itself, but I haven't been > able to find one so far. > > Thanks, > Dan > > -- 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/0af75144-4837-44fc-8854-a41a769b5706n%40googlegroups.com.