Assume I have a third-party type that implements a flow-style interface, i.e. calling a function on a pointer function update the state and returns the pointer back:
type ThirdPartyType struct {}
func NewThirdPartyType() *ThirdPartyType {
return &ThirdPartyType{}
}
func (tpt *ThirdPartyType) Foo(foo string) *ThirdPartyType {
// ...
return tpt
}
Using such a type is succinct:
tpt := NewThirdPartyType().Foo("foo")
I want to wrap this ThirdPartyType
and add a few new methods. For this I embed it into MyType
like
type MyType struct {
*ThirdPartyType
}
func NewMyType() *MyType {
return &MyType{}
}
func (mt *MyType) Bar(bar string) *MyType {
// ...
return mt
}
While for my custom methods I can retain the flow style, I cannot for the ones “inherited” by ThirdPartyType
as they return *ThirdPartyType
and thus cannot be used in the chain:
var mt *MyType = NewMyType().Bar("bar")
mt.Foo("foo")
This is rather unfortunate as it defeats the succinctness I had before. The only solution I found so far is to re-implement the methods of ThirdPartyType
on MyType
like:
func (mt *MyType) Foo(foo string) *MyType {
mt.Foo(foo)
return mt
}
Now I can in fact do
mt := NewMyType().Bar("bar").Foo("foo")
However, this is quite a bit of boilerplate. Plus, the number of methods I’d need to re-implement is around 50, so I’d rather not maintain this by hand.
The best solution I came up with is to use code generation coupled with reflect
to handle this automatically. I just want to check if I’m missing a simpler solution before I go down this route.