Golang composition
These are some notes I took while experimenting and playing around with Golang further. This article is mainly exploring embedded structs and interfaces to experiment how they work etc.
Use Golang playground in order to see how it works in action
One can combine golang interfaces together to form large interfaces.
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type ZZZ struct{}
func (z ZZZ) Hahax() {
fmt.Println("ZZZ Hahax")
}
func (z ZZZ) Miao() {
fmt.Println("ZZZ Miao")
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
- Interface
CCC
is formed from interfaceAAA
andBBB
- In order to fulfill requirements of
CCC
, structZZZ
needs to implement both theHahax
andMiao
functions. - In order to understand where each function is being called from, we would have the function print out which struct it comes from and the name of its function.
The following code outputs the following
ZZZ Hahax
ZZZ Miao
We can take apart struct ZZZ
and compose it from multiple structs instead
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type DD1 struct{}
func (z DD1) Hahax() {
fmt.Println("DD1 Hahax")
}
type DD2 struct{}
func (z DD2) Miao() {
fmt.Println("DD2 Miao")
}
type ZZZ struct {
DD1
DD2
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
- Interface
CCC
is formed from interfaceAAA
andBBB
- In order to fulfill requirements of
CCC
, structZZZ
needs to implement both theHahax
andMiao
functions. - Struct
ZZZ
is composed of structsDD1
andDD2
.DD1
implements theHahax
method whileDD2
implements theMiao
method - Similarly, in order to understand where each function is being called from, we would have the function print out which struct it comes from and the name of its function.
The following code would output the following:
DD1 Hahax
DD2 Miao
However, let’s experiment further. What if ZZZ
which is already composed DD1
and DD2
(which fulfills the requirements of CCC
) also implements the Hahax
function?
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type DD1 struct{}
func (z DD1) Hahax() {
fmt.Println("DD1 Hahax")
}
type DD2 struct{}
func (z DD2) Miao() {
fmt.Println("DD2 Miao")
}
type ZZZ struct {
DD1
DD2
}
func (z ZZZ) Hahax() {
fmt.Println("ZZZ Hahax")
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
The above code outputs the following instead.
ZZZ Hahax
DD2 Miao
Notice how as compared to previous situation, instead of printing out DD1 Hahax
, it prints out ZZZ Hahax
instead. So, there is some sort of level of hierarchy when functions are being called. If the list of function within that level has the Hahax
function, it would call it; else, it would go down through the structs embedded within it and call it accordingly.
Now, let’s experiment further. What if DD2
does not implement the Miao
function but instead, it embeds DD3
which then implements the Miao
function?
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type DD1 struct{}
func (z DD1) Hahax() {
fmt.Println("DD1 Hahax")
}
type DD2 struct {
DD3
}
type DD3 struct{}
func (z DD3) Miao() {
fmt.Println("DD3 Miao")
}
type ZZZ struct {
DD1
DD2
}
func (z ZZZ) Hahax() {
fmt.Println("ZZZ Hahax")
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
And as expected, the following code outputs the following:
ZZZ Hahax
DD3 Miao
Apparently, it would recurse down the embedded structs and use the first Miao
function observed.
If somehow, DD1
also implements the Miao
function, that it would it be expected that the DD3 Miao
would not be printed but DD1 Miao
would be printed instead.
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type DD1 struct{}
func (z DD1) Hahax() {
fmt.Println("DD1 Hahax")
}
func (z DD1) Miao() {
fmt.Println("DD1 Miao")
}
type DD2 struct {
DD3
}
type DD3 struct{}
func (z DD3) Miao() {
fmt.Println("DD3 Miao")
}
type ZZZ struct {
DD1
DD2
}
func (z ZZZ) Hahax() {
fmt.Println("ZZZ Hahax")
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
The following is the output for this piece of code:
ZZZ Hahax
DD1 Miao
Let’s remove DD3
from the latest iteration of the code and also have DD2
also implement the Miao
function. That would make it confusing - which Miao
function should be used when since DD1
and DD2
embedded struct appear to be on the same level?
package main
import (
"fmt"
)
type AAA interface {
Hahax()
}
type BBB interface {
Miao()
}
type CCC interface {
AAA
BBB
}
type DD1 struct{}
func (z DD1) Hahax() {
fmt.Println("DD1 Hahax")
}
func (z DD1) Miao() {
fmt.Println("DD1 Miao")
}
type DD2 struct {}
func (z DD2) Miao() {
fmt.Println("DD2 Miao")
}
type ZZZ struct {
DD1
DD2
}
func (z ZZZ) Hahax() {
fmt.Println("ZZZ Hahax")
}
func Printer(c CCC) {
c.Hahax()
c.Miao()
}
func main() {
z := ZZZ{}
Printer(z)
}
We now have the following:
./prog.go:52:9: ZZZ.Miao is ambiguous
./prog.go:52:9: cannot use z (type ZZZ) as type CCC in argument to Printer:
ZZZ does not implement CCC (missing Miao method)
Even the golang runtime becomes unsure of which one to run and it panics.