I have two types, B and C, which share all methods, but implement one of them differently. I would like to express this by having a parent type A, containing the implementations of the shared methods, and embedding A in B and C. (Don't Repeat Yourself!) The snag is that the method that differs between B and C is called in many of the shared methods. What's the idiomatic way to structure such code?
My current implementation looks essentially like this (https://play.golang.org/p/RAvH_hBFDN; based on an example by Dave Cheney):
package main
import (
"fmt"
)
type Legger interface {
Legs() int
}
type Cat struct {
Name string
L Legger
}
// Cat has many methods like this, involving calling c.L.Legs()
func (c Cat) PrintLegs() {
fmt.Printf("I have %d legs.\n", c.L.Legs())
}
// OctoCat is a Cat with a particular implementation of Legs
type OctoCat struct {
Cat
}
func (c OctoCat) Legs() int {
return 8
}
// TetraCat has a different implementation of Legs
type TetraCat struct {
Cat
}
func (c TetraCat) Legs() int {
return 4
}
func main() {
c := TetraCat{Cat{"Steve",nil}}
c.L = &c
c.PrintLegs() // want 4
o := OctoCat{Cat{"Bob",nil}}
o.L = &o
o.PrintLegs() // want 8
}
The type definitions themselves look nice and clean, but the initialization code in main is wacky (first the nil in the struct literal, then c.L = &c, what?). Is there a better solution?
A similar pattern was presented in is it possible to call overridden method from parent struct in golang?, but the question of whether this is the idiomatic way to proceed was not answered.
Two approaches I would consider for solving this:
1. Refactor your code to have a single type Cat with the fields Name string and Legs int:
package main
import (
"fmt"
)
type Cat struct {
Name string
Legs int
}
func (c *Cat) PrintLegs() {
fmt.Printf("I have %d legs.\n", c.Legs)
}
func main() {
c := &Cat{"Steve", 4}
c.PrintLegs() // want 4
o := &Cat{"Bob", 8}
o.PrintLegs() // want 8
}
https://play.golang.org/p/_PNAu3sgG8
2. Do away with the Cat type and just have TetraCat and OctoCat implement the Legger interface:
package main
import (
"fmt"
)
type Legger interface {
Legs() int
}
func PrintLegs(l Legger) {
fmt.Printf("I have %d legs.\n", l.Legs())
}
// OctoCat is a Cat with a particular implementation of Legs
type OctoCat struct {
Name string
}
func (c *OctoCat) Legs() int {
return 8
}
// TetraCat has a different implementation of Legs
type TetraCat struct {
Name string
}
func (c *TetraCat) Legs() int {
return 4
}
func main() {
c := &TetraCat{"Steve"}
PrintLegs(c) // want 4
o := &OctoCat{"Bob"}
PrintLegs(o) // want 8
}
https://play.golang.org/p/m4QvKhSj0w
Related
this question is related to Passing struct with anonymous field in Go but different in that I am dealing with a function that handles an array of Parent items rather than just one struct, ie:
package main
import "fmt"
type Parent struct {
Dad string
}
type Child struct {
Parent
Son string
}
func myfunc(data []Parent) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].Dad)
}
}
func main() {
data := make([]Child, 2)
data[0].Dad = "pappy"
data[0].Son = "sonny"
data[1].Dad = "daddy"
data[1].Son = "billy"
myfunc(data)
}
I tried to cast data to an array of Parents like myfunc([]Parent(data)) but that didnt work and obviously the solution of myfunc(data.Parent) wont work on an array.
Is there a reasonable solution to this in golang without resorting to creating a new slice or generics which are not out of beta yet?
Cheers
You cannot do this even with generics. data[n].Dad will not work.
The reasonable way to deal with it is to use an interface, but still, you have to create an interface slice for it:
type WithDad interface {
GetDad() string
}
func (p Parent) GetDad() string {return p.Dad}
func myFunc(data []WithDad) {
...
}
...
arr:=make([]WithDad,0,len(data))
for _,x:=range data {
arr=append(arr,x)
}
myFunc(arr)
The reason for this is how the type system works and how slices are passed around. The slice []Child points to an array where each entry is a Child. A function that takes []Parent expects a slice whose elements are Parent, which is a different type, so you cannot pass one for the other.
The slice []WithDad points to an array where each entry is an interface. Each such entry points to the Child or Parent entry in another slice.
Just for completeness I made a complete version of Burak Serdar code I got working (I like it when full working examples are posted for me to cut and paste later :P) ... note I deliberately return a pointer to the Parent because in practice its likely you will want to work on that complete struct and not just read 1 field.
package main
import "fmt"
type WithDad interface {
GetDad() *Parent
}
type Parent struct {
Dad string
}
func (p *Parent) GetDad() *Parent {
return p
}
type Child struct {
Parent
Son string
}
func (c *Child) GetDad() *Parent {
return &c.Parent
}
func myfunc(data []WithDad) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
}
}
func main() {
data := make([]WithDad, 2)
data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
myfunc(data)
}
Your structure with Child being a composite of Parent and a string (which I guess contains the name) makes little sense. A child is not a parent plus their name. In fact you only have one concept, namely Person, who potentially has a parent. Please consider the following approach:
package main
import "fmt"
type Person struct {
Name string
Parent *Person
}
func myfunc(data []Person) {
for n, _ := range data {
fmt.PrintLn("My name is", n.Name)
if n.Parent != nil {
fmt.PrintLn("My dad is", n.Parent.Name)
}
}
}
func main() {
data := make([]Person, 2)
data[0].Name = "daddy"
data[1].Name = "billy"
data[1].Parent = &data[0]
myfunc(data)
}
I want to merge some similar func code to one func, but every old func is use different type of struct, so i intend to create the model by different string of type.
SO i do something like this:
type A struct {
filed string
}
type B struct {
filed string
}
and still C, D, E, F here...(every struct has its own method different with others)
and i want create those type in one place:
create(typeName string) interface {
switch typeName {
case A:
return &A{}
case B:
return &B{}
....(more case than 10 times)
}
}
Then i use the create() here:
model := create("A")
now, model is type of interface, and no A`s fileds, how would simply to recover the type of model to A
Here is a sample of how you can use type assertion to convert interfaces to underlying structs
Here e is of the struct type and hence you can access any of its fields or struct methods.
package main
import (
"fmt"
)
type A struct {
AF int
}
type B struct {
BF string
}
func main() {
ds := []interface{}{
A{1},
B{"foo"},
}
for _, d := range ds {
switch e := d.(type) {
case A:
fmt.Println(e.AF)
case B:
fmt.Println(e.BF)
}
}
}
I am fairly new to Go and I have been doing OOP for a long time. Now, I understand that inheritance is done via composition but ... I'd like to send a specialization in a function expecting a generalization as such:
package main
import (
"fmt"
)
type A struct {
ONE int
}
type B struct {
A
ANOTHER int
}
func main() {
fmt.Println("Hello, playground")
a := A{1}
b := B{a, 2}
fmt.Println(a.ONE)
fmt.Println(b.ANOTHER)
takeA(&b)
}
func takeA(a *A) {
fmt.Println(a.ONE)
}
Sure, I can do takeA(&b.A) but it defeats the hierarchy I am trying to set up as some A fields/method could be shadowed in B.
Is there a way around this? Or should I create a dumb interface such as:
package main
import (
"fmt"
)
type A struct {
ONE int
}
func (a A) getOne() int{
return a.ONE
}
type B struct {
A
ANOTHER int
}
type HasOne interface {
getOne() int
}
func main() {
fmt.Println("Hello, playground")
a := A{1}
b := B{a, 2}
fmt.Println(a.ONE)
fmt.Println(b.ANOTHER)
takeA(b)
}
func takeA(a HasOne) {
fmt.Println(a.getOne())
}
There is no inheritance in Go. Composition doesn't give you dynamic dispatch (which is usually implied when 'polymorphism' and 'inheritance' are used in the same paragraph): the embedded method call always happens on the embedded field as a receiver, not on the container type it is embedded into.
I wonder how the following functions lengthAA and lengthBB can be simplified to just one function. Note in those two functions it just compute the length of the array, it is just an example and can be more complicated than that. Ideally, I want only one function that serve the same purpose (in this case, len) but can take different struct as variable.
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func lengthAA(aa AA) int {
return len(aa)
}
func lengthBB(bb BB) int {
return len(bb)
}
The Go way of doing this would be for both AA and BB to implement a common method. length would then accept an interface that contains the same function signature. Example:
package main
import (
"fmt"
)
type Lengther interface {
Length() int
}
type A struct {
id string
}
type AA struct {
ids []A
}
func (a *AA) Length() int {
return len(a.ids)
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func (b *BB) Length() int {
return len(b.ids)
}
func length(l Lengther) int {
return l.Length()
}
func main() {
aa := &AA{
ids: make([]A, 10),
}
bb := &BB{
ids: make([]B, 34),
}
fmt.Println(length(aa))
fmt.Println(length(bb))
}
https://play.golang.org/p/DdxP5lFcZi
1- Using two separate receiver methods length() like this working sample code (This is idiomatic Go):
package main
import "fmt"
func (v *AA) length() int {
return len(v.ids)
}
func (v *BB) length() int {
return len(v.ids)
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(aa.length()) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(bb.length()) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
2- Using one length(aa interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
func length(aa interface{}) int {
switch v := aa.(type) {
case AA:
return len(v.ids)
case BB:
return len(v.ids)
}
return -1
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
3- Using reflect and one length(v interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
import "reflect"
func length(v interface{}) int {
return reflect.ValueOf(v).FieldByName("ids").Len()
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
output:
2
2
This code wouldn't actually compile since len(aa) would be passing a struct to len which would fail. But I think I get what you're trying to do, and the best way to do it is with the nearest thing Go has to inheritance, which is really just struct embedding.
By making an embeddable struct, and having each of your structs that have that similar feature embed it, you can reduce the line count of the code, though "simplifying" may be a bit of a stretch.
type HasIDs struct {
Ids []string
}
type AA struct {
HasIDs
OtherValues []int
}
type BB struct {
HasIDs
OtherValues []byte
}
At this point both structs AA and BB have the value Ids []string. Now you can give the HasIDs struct a method that both structs should be able to call.
func (hasIds HasIDs) length() {
return len(hasIds.Ids)
}
And call the method on either struct that embeds the struct with the method.
a1 := AA{}
aLength := a1.length()
Here is a working code sample: https://play.golang.org/p/ys_CN_L_cr
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
}