Go generics: self-referring interface constraint - go

I have a couple custom types that I need to process in the same way. It seems like a perfect use for generics. In the process, I need to call methods on instances of the types, and those methods return different instances of the same types, and then I need to call methods on those returned instances, which I can't get to work. For the purpose of this question, I've fabricated a much simpler set of types and a process that exemplifies the problem I'm running in to.
Here's a working example without generics that shows the types (Circle and Square), and a process (.Bigger().Smaller()) I'll be trying to abstract into a generic function later (online demo):
package main
import (
"fmt"
)
type Circle struct{ r float64 }
func NewCircle(r float64) *Circle { return &Circle{r: r} }
func (c *Circle) Radius() float64 { return c.r }
func (c *Circle) Bigger() *Circle { return &Circle{r: c.r + 1} }
func (c *Circle) Smaller() *Circle { return &Circle{r: c.r - 1} }
type Square struct{ s float64 }
func NewSquare(s float64) *Square { return &Square{s: s} }
func (s *Square) Side() float64 { return s.s }
func (s1 *Square) Bigger() *Square { return &Square{s: s1.s + 1} }
func (s1 *Square) Smaller() *Square { return &Square{s: s1.s - 1} }
func main() {
fmt.Println(NewCircle(3).Bigger().Smaller().Radius()) // prints 3
fmt.Println(NewSquare(6).Bigger().Smaller().Side()) // prints 6
}
The first thing I do to make a generic function is to define a type constraint:
type ShapeType interface {
*Circle | *Square
}
I'll be passing a ShapeType to a process method, and I need to be able to call methods on the ShapeType instance, so I need to define another type constraint which specifies the methods that can be called on a ShapeType:
type Shape[ST ShapeType] interface {
Bigger() ST
Smaller() ST
}
With these, I can write a process method (online demo):
func process[ST ShapeType](s Shape[ST]) ST {
return s.Bigger().Smaller()
}
This fails to compile however, as the return value of s.Bigger() is an ST, not a Shape[ST], so go doesn't know that it can then call Smaller() on the return value of s.Bigger(). In go's words:
s.Bigger().Smaller undefined (type ST has no field or method Smaller)
If Bigger() and Smaller() didn't return instances of their receiver types, I could write:
type Shape interface {
*Circle | *Square
Bigger()
Smaller()
}
func process[S Shape](x S) S {
x.Bigger().Smaller()
return x // I guess we wouldn't even have to return x, but just for example's sake
}
Instead I would need to write:
type Shape interface {
*Circle | *Square
Bigger() Shape
Smaller() Shape
}
and it appears go doesn't like self-referential type constraints.
If it were possible to assert/convert a concrete type to an interface it conforms to, then I could make it work, but it doesn't appear to be possible to do that (online demo):
func process[ST ShapeType](s Shape[ST]) ST {
s1 := s.Bigger()
s2 := s1.(Shape[ST]) // go is not happy here
return s2.Smaller()
}
For this, go says:
cannot use type assertion on type parameter value s1 (variable of type ST constrained by ShapeType)
I don't know what else to try.
Is it possible to work with these kinds of types with generics? If so, how?

Combine your two attempted interfaces together:
type Shape[ST any] interface {
*Circle | *Square
Bigger() ST
Smaller() ST
}
And then instantiate the constraint of process with the type parameter itself:
func process[ST Shape[ST]](s ST) ST {
return s.Bigger().Smaller()
}
Adding the union element *Circle | *Square into Shape[ST any] means that only those two types will be able to implement the interface
Then using the type parameter in the method signature, like Bigger() ST, means that whichever type is passed has a method that returns itself.
If you want to keep ShapeType as a separated interface, you can write Shape as:
type Shape[ST any] interface {
ShapeType
Bigger() ST
Smaller() ST
}
You can also use process method with type inference, without any issue:
func main() {
c1 := NewCircle(3)
c2 := process(c1)
fmt.Println(c2.Radius()) // prints 3 as expected
fmt.Printf("%T\n", c2) // *main.Circle
s1 := NewSquare(6)
s2 := process(s1)
fmt.Println(s2.Side()) // prints 6 as expected
fmt.Printf("%T\n", s2) // *main.Square
}
Final playground: https://go.dev/play/p/_mR4wkxXupH

Related

Chainable struct methods that satisfies multiple interfaces?

I have a need to create multiple structs with almost the same fields and methods with the same actions. Instead of doing that I thought, why not create a single struct and use interfaces to limit interactions. It worked great! Now the problem. I want the methods to be chainable. To do that, methods need to return a reference to the struct. After doing that, all the returns complain that (struct) does not implement <interface> (wrong type for <method> method). Which is expected.
The question is, is it possible to use a single struct with multiple interfaces that has chainable methods? Or is creating individual, duplicate, structs for every interface the only way?
I thought of using composition but I still need to define methods that will call the embedded struct methods, in which case there's no difference to creating new pure structs.
Example problem:
https://play.golang.org/p/JrsHATdi2dr
package main
import (
"fmt"
)
type A interface {
SetA(string) A
Done()
}
type B interface {
SetB(string) B
Done()
}
type t struct {
a string
b string
}
func (t *t) SetA(a string) *t { t.a = a; return t }
func (t *t) SetB(b string) *t { t.b = b; return t }
func (t *t) Done() { fmt.Println(t.a, t.b) }
func NewTA() A {
return &t{}
}
func NewTB() B {
return &t{}
}
func main() {
fmt.Println("Hello, playground")
ta := NewTA()
ta.SetA("a")
ta.Done()
tb := NewTB()
tb.SetB("b")
tb.Done()
}
When you use *t as return type in SetA and SetB that means t are not implement A and B interface. The signature of SetA and SetB function of *t doesn't match with interface A and B accordingly.
Accually SetA(a string) A and SetA(a string) *t are not same think. You used A as return type for SetA in interface but use *t as return type for t, go doesn't support this. Same for SetB function
If you do like this then it will work because now function signature matched
func (t *t) SetA(a string) A { t.a = a; return A(t) }
func (t *t) SetB(b string) B { t.b = b; return B(t) }
Code in go playground here

Structs and interface types

Could someone please explain (or if it's a long thing to explain at least point me to some documentation) why this code is behaving like it does. It's a bit lengthy but I couldn't figure out a good way of shortening it without losing too much info.
What confuses me is that I need to have the method "Find" on each type of struct for it to be recognized as the type it is. With Find on only the baseTypeImp is it printing that each is baseTypeImp, if I have it on baseTypeImp and advancedBaseTypeImp are those two identified correctly, but not the last type.
PlaygroundLink
My Code
package main
import (
"fmt"
"reflect"
)
type BaseType interface {
Name() string
Find(string) BaseType
Children() []BaseType
Options()
}
type baseTypeImp struct {
name string
children []BaseType
}
func (b baseTypeImp) Options() {
fmt.Println("Not implemented")
}
func (b baseTypeImp) Find(name string) BaseType {
if b.name == name {
return b
}
for _, c := range b.children {
if m := c.Find(name); m != nil {
return m
}
}
return nil
}
func (b baseTypeImp) Name() string {
return b.name
}
func (b baseTypeImp) Children() []BaseType {
return b.children
}
type AdvancedBaseType interface {
Value()
}
type advancedBaseTypeImp struct {
baseTypeImp
}
func (a advancedBaseTypeImp) Options() {
fmt.Println("Is implemented")
}
func (a advancedBaseTypeImp) Value() {
fmt.Println("Value called")
}
func (a advancedBaseTypeImp) Find(name string) BaseType {
if a.name == name {
return a
}
for _, c := range a.children {
if m := c.Find(name); m != nil {
return m
}
}
return nil
}
type reallyAdvancedBaseTypeImp advancedBaseTypeImp
func newThingy(name, variant string, children []BaseType) BaseType {
base := baseTypeImp{name: name, children: children}
switch variant {
case "advanced":
return advancedBaseTypeImp{baseTypeImp: base}
case "reallyAdvanced":
return reallyAdvancedBaseTypeImp{baseTypeImp: base}
}
return base
}
func whatType(b BaseType) {
if b == nil {
return
}
fooType := reflect.TypeOf(b)
fmt.Println(b.Name(), " is type ", fooType.Name())
b.Options()
}
func main() {
advanced := make([]BaseType, 0, 5)
for i := 0; i < 5; i++ {
advanced = append(advanced, newThingy(fmt.Sprintf("Advanced %d", i), "advanced", nil))
}
reallyAdvanced := make([]BaseType, 0, 2)
for i := 0; i < 2; i++ {
reallyAdvanced = append(reallyAdvanced, newThingy(fmt.Sprintf("ReallyAdvanced %d", i), "reallyAdvanced", advanced[i:i+3]))
}
basic := newThingy("Basic parent", "basic", reallyAdvanced)
whatType(basic.Find("Basic parent"))
for i := 0; i < 2; i++ {
whatType(basic.Find(fmt.Sprintf("Advanced %d", i)))
whatType(basic.Find(fmt.Sprintf("ReallyAdvanced %d", i)))
}
}
The output now is:
Basic parent is type baseTypeImp
Not implemented
Advanced 0 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 0 is type baseTypeImp
Not implemented
Advanced 1 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 1 is type baseTypeImp
Not implemented
What I'd like to have is:
Basic parent is type baseTypeImp
Not implemented
Advanced 0 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 0 is type reallyAdvancedBaseTypeImp
Is implemented
Advanced 1 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 1 is type reallyAdvancedBaseTypeImp
Is implemented
Is there a way to get this working without having to implement Find on each level? It kind of defeats the purpose of having the common methods in the top layer struct. And of course, if possible explain why it's behaving the way it does.
When you embed a struct into another one, the outer struct gets the methods of the embedded one.
type inner struct {
}
func (i inner) f() {}
type outer struct {
inner
}
...
x:=outer{}
x.f()
You can think of this as syntactic sugar for:
type outer2 struct {
i inner
}
y.i.f()
When you embed inner without a field name, you simply drop the i in the call. You can still call x.inner.f() in the first example.
When you redefine a type, it does not get the methods defined for its base type.
type newtype inner
newtype does not have f() defined. However, if inner also embeds other structs (like you do), then those are still embedded in the new type, so those function are defined:
type deepest struct {}
func (deepest) deep() {}
type inner struct{}
func (inner) in() {}
type outer inner
Above, the type outer does not have the function in, but it has deep.
So when you call reallyAdvancedBaseTypeImp.Find(), what you're really doing is reallyAdvancedBaseTypeImp.baseTypeImp.Find(), which works on that portion of the struct. That's why you're getting the types you get.
You're trying to emulate method overriding. You can't really do that. Formulate your problem in a different way.

How can I store types in go maps for initialisation at a later stage

I'm trying to implement a factory function that will return an instance of one of many structs that fulfil the contract of an interface X.
m := make(map[string] ?)
func init () {
m["a"] = ?
m["b"] = ?
}
type X interface {
y()
}
type A struct {}
func (a * A) y () {}
type B struct {}
func (b * B) y () {}
function factory(name string) X {
return &m[name]{}
}
The code above is just a simplified demonstration of what I'm trying to achieve - looking for pointers for whether this is possible, or if there is a different go idiom to solve this kind of requirement that I'm missing.
You can use map[string]X, with X the interface (which can reference a value or a pointer of any object respecting X contract)
or if there is a different go idiom to solve this kind of requirement that I'm missing?
You can also use reflection (as in "Instance new Type") to implement your factory.
reflect.New(yourtype).Elem().Interface()
You can see a factory example in "is there a way to create an instance of a struct from a string?".
The quicker approach for a factory method (returning a new instance each time) is using a switch (like in this example):
// Create a new Widget interface based on WidgetType and set WidgetInfo
func New(wt WidgetType, wi WidgetInfo) Widget_iface {
switch wt {
case Widget_A:
return newWidgetA(wi)
case Widget_B:
return newWidgetB(wi)
}
return nil
}
If you have a simple value type then as #VonC said, you can just use map[string]X and return a copy of the exemplar value.
For anything else, instead of using reflection, I'd just use a map of creation functions. Like what the image package does with
image.RegisterFormat.
E.g. (playground):
package main
import "fmt"
type X interface {
y()
}
type newXFunc func() X
// Here just a map variable and two functions, but
// this could be a type with two methods instead.
var m = map[string]newXFunc{}
func register(name string, fn newXFunc) {
m[name] = fn
}
func factory(name string) X {
return m[name]()
}
func init() {
// If register is exported than these
// calls can be in other packages that
// implement A and B.
register("a", NewA)
// For simple things that don't have/need
// their own stand-alone "new" function.
register("b", func() X { return B{} })
}
type A struct{}
func (a *A) y() {}
func NewA() X { return &A{} }
type B struct{}
func (b B) y() {}
func main() {
a1 := factory("a")
b1 := factory("b")
fmt.Printf("%T\n", a1)
fmt.Printf("%T\n", b1)
}

How to realize Virtual Inheritance in Go

How to realize "Virtual Inheritance" in Go?
go lang compiler version: "1.3.1 windows/amd64", does it support "Virtual Inheritance" for Go?
I never heard a C like language could support "Virtual", so I really misunderstand.
Virtual Inheritance solves a problem which does not exist if you don't have multiple inheritance. Consider the following inheritance tree:
A
/ \
B C
\ /
D
If classes B and C both provide a data-member (or method for that matter) with the same name then when accessing said member in D, you need a way to disambiguate whose ancestor's data-member (or method) you wish to access.
Virtual Inheritance is C++'s solution.
In Go you don't have inheritance to begin with; only composition and you can embed at most 1 member of any given type at once.
http://play.golang.org/p/1iYzdoFqIC
package main
type B struct {
}
func (b B) Foo() {}
type C struct {
}
func (c C) Foo() {}
type D struct {
B
C
}
func main() {
d := D{B{}, C{}}
// d.Foo() // <- ambiguous
d.B.Foo() // <- ok
d.C.Foo() // <- ok
}
Virtual Inheritance not only solves the problem of multiple inheritance but also gives us polymorphism.
package main
import (
"fmt"
"math"
)
type Form interface {
Color() string
Area() float64
}
type form struct {
color string
}
func (f *form) Color() string {
return f.color
}
type Circle struct {
form
radius float64
}
func (k *Circle) Area() float64 {
return math.Pi * k.radius * k.radius
}
type Rectangle struct {
form
width, height float64
}
func (r *Rectangle) Area() float64 {
return r.width * r.height
}
func main() {
var forms [2]Form
forms[0] = &Circle{
form: form{ "black" },
radius: 5.0,
}
forms[1] = &Rectangle{
form: form{ "read" },
width: 2.0,
height: 3.0,
}
for _, f := range forms {
fmt.Printf("%s: %.2f\n", f.Color(), f.Area())
}
}
Here we have an array of things that have something in common (Color and Area) and we can just iterate over this array calling the same functions and always the right thing will happen.
This is just one advantage of polymorphism. It plays a big role in most design patterns.
"Virtual Inheritance" is something more like this
http://play.golang.org/p/8RvPmB3Pof
package main
type A struct {
virtual int
}
func (a *A) set(v int) {
a.virtual = v
}
func (a *A) get() int {
return a.virtual
}
type B struct {
*A
}
type C struct {
*A
}
type D struct {
*B
*C
}
func main() {
a := &A{}
b := &B{a}
c := &C{a}
d := &D{b, c}
d.B.set(3)
println(d.C.get())
return
}

Why can't a method be defined both for a struct and its pointer?

Given the setup in the 54th slide of the golang tour:
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Why can't a method also be defined for the struct as well as the pointer to the struct? That is:
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Defining this gives the following error:
prog.go:41: method redeclared: Vertex.Abs
method(*Vertex) func() float64
method(Vertex) func() float64
It can. Just define it on the struct and not the pointer. It will resolve both ways
Method Sets
The method set of the corresponding pointer type *T is the set of all
methods with receiver *T or T (that is, it also contains the method
set of T)
Try live: http://play.golang.org/p/PsNUerVyqp
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{5, 10}
v_ptr := &v
fmt.Println(v.Abs())
fmt.Println(v_ptr.Abs())
}
Update: As per comments I have created an extra example that actually makes use of the Abser interface to illustrate that both the value and the pointer satisfy the interface.
https://play.golang.org/p/Mls0d7_l4_t
While considering for example:
type T U
func (t *T) M() int { return 1 }
var t T
...we can now invoke M() on t by writing t.M() as the language permits to call a method with a pointer receiver even on its underlying (non pointer) typed instances, i.e. it becomes equivalent to (&t).M().
If it will be permitted to now additionaly define:
func (t T) M() int { return 2 }
...then there's no way to tell what is now t.M() supposed to return.

Resources