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.

Reply via email to