I'm coming from a language like C++ where OOP is well defined and polymorphism is commonly used. I'm new using Go and I'm trying to call child method from a polymorphism and I have no idea what's is the right pattern.
I created two structs as u'll see, and I defined 2 methods fun1 and fun2 where in the base struct i override only one of them, and in the parent i'm calling it. If the polymorphism is correct, this child method should be called and at least in my example, this is not happenning
Here is the code:
package main
import (
"fmt"
)
type A struct {
}
type B struct {
A
}
func (a* A) fun1() {
fmt.Println("I'm in A.fun1()")
a.fun2()
}
func (a* A) fun2() {
fmt.Println("I'm in A.fun2()")
}
func (b* B) fun2() {
fmt.Println("I'm in B.fun2()")
}
func main() {
b := B{}
b.fun1()
}
You can try it here: https://play.golang.org/p/s7xZun-6Otx
The output was
I'm in A.fun1()
I'm in A.fun2()
and I wasexpected
I'm in A.fun1()
I'm in B.fun2()
How can I do that? what's the right way for having a good design in Go for this?
Regards
Go objects are generally built around composition as opposed to inheritance, as the pattern you are using would make it very difficult for the A
structure to make any assumptions about what fun2
is doing. The polymorphism in go is done at the interface level. The preferred method is to pull the "overridable" fun2
functionality into a separate interface type, which is passed in to the fun1
function or stored in the object containing fun1
. Without the specifics of how you would be doing this, it's difficult to make a reasonable example but this is the pattern:
package main
import (
"fmt"
)
type fun2er interface {
fun2()
}
type A struct {
B fun2er
}
func (a* A) fun1() {
fmt.Println("I'm in A.fun1()")
a.B.fun2()
}
type B1 struct {}
func (b B1) fun2() {
fmt.Println("I'm in B1.fun2()")
}
type B2 struct {}
func (b B2) fun2() {
fmt.Println("I'm in B2.fun2()")
}
func main() {
a1 := A{B: B1{}}
a2 := A{B: B2{}}
a1.fun1()
a2.fun1()
}
This will print:
I'm in A.fun1()
I'm in B1.fun2()
I'm in A.fun1()
I'm in B2.fun2()
Edit:
I wanted to add a little more color on how this works under the hood. The way you are "extending" your A
type with B
is called struct embedding, and is mostly syntactic sugar for adding a field to B
of type A
named the same as its type:
type A struct {}
type B struct {
A A
}
The key difference being that when using struct embedding you can call A
methods directly on a B
object b.fun1()
. When this is called, the this-like a
parameter that gets passed to fun1
is not the entire B
object, but just the A
field inside of it (as though you called b.A.fun1()
) which is why when fun1
calls fun2
, it is calling the A
implementation, as it has no access to the B
object it is stored inside.