How to deal with repetitiveness and flexibility when implementing Go interfaces? - go

I have a project that uses a structure like so:
type I interface {
GetName() string
DoSomething()
}
//
// A implements I
//
type A struct {
Name string
}
func (a *A) GetName() string {
return a.Name
}
func (a *A) DoSomething() {
...do something
}
//
// B implements I
//
type B struct {
Name string
}
func (b *B) GetName() string {
return b.Name
}
func (b *B) DoSomething() {
...do something
}
func (b *B) DoSomethingElse() {
...do something else
}
//
// Both
//
func UseAorB(T I) {
name := T.GetName()...
}
Is using GetName the best way to get the name field from either struct A or B when called in a function that takes interface I?
Do I have to redefine DoSomething every time for each thing that is meant to implement the interface? Or is there a better way to do this if DoSomething is the same every time where I can define it just once?
Struct B has a method that the interface does not define (DoSomethingElse). Do I need to use reflect to be able to pass Struct B to a function that takes interface I to call DoSomethingElse? Or should I be defining a new interface that includes this method?
I want to improve my code quality and write a solid library, but I have to say it feels like I am fighting the language and making my life more difficult.

Yes, GetName() is a good way of doing that
If you have similar implementations of a method, you can usually move it to a common struct and embed that:
type Common struct {}
func (c Common) DoSomething() {...}
type A struct {
Common
Stuff
}
type B struct {
Common
Other stuff
}
Above, both A and B have DoSomething method, and they share the implementation
Do not use reflect. There are two ways:
Use type assertion:
func f(in I) {
if b, ok:=in.(B); ok {
// b is of type B, so:
b.DoSomethingElse()
}
}
Use an interface and type assertion:
type DoesSometingElse interface {
DoSomethingElse()
}
func f(in I) {
if x, ok:=in.(DoesSomethingElse); ok{
x.DoSomethingElse()
}
}
If you feel like you're fighting with the language, then either you are modeling something incorrectly, or you don't know the right way to do something in that language. There are good and bad ways of doing things in all languages, and many times these are different for each language. If you are coming to Go from another language, you should first stop trying to think in that other language and translate to Go, and try to work with Go alone.

Related

Import cycles more than two levels go

So i have this import cycle to solve, and my project structure basically likes this:
model.go -> procedure.go -> function.go
In my function i need model and i use interface to handle it. Currently my code basically like this:
type imodel interface {
foo()
}
type model struct {
}
func (m *model) run() {
proc := &procedure{}
proc.run(m)
}
func (m *model) foo() {
//bla bla
}
type procedure struct {
}
func (p *procedure) run(model imodel) {
funct := &function{}
funct.run(model)
}
type function struct {
}
func (f *function) run(model imodel) {
model.foo()
}
My question is should i pass my model using interface thorough every class like that or there's any other workaround?
I would put all of these in the same package. Depending on circumstances, I may put them in different files in the same package.
Also, you do not seem to export imodel, so it would be package-internal and unless you have multiple concrete implementations, you do not need an interface. Then, "imodel" is a less than ideal name, the interface should be named model and each concrete type implementing the interface should be named after what it models.

How to use reflect and interface{} to implement polymorphism of methods with argument in Golang?

I am porting some code from C++ to golang. I did some research on OOP and polymorphism in golang, all suggest using interface and embedding to implement polymorphism. I have a sample code written as follows
type Worker interface {
Show()
Inc()
}
type WorkerA struct {
x int
Worker // embed all methods in interface
}
type WorkerB struct {
WorkerA // embed WorkerA to have all methods
}
func (a *WorkerA) Inc() {
a.x++
}
func (a WorkerA) Show() {
fmt.Println("A:", a.x)
}
func (b WorkerB) Show() {
fmt.Println("B:", b.x)
}
func main() {
list := make([]Worker, 10)
for n:=0; n<len(list); n++ {
if n%2==0 {
list[n] = &WorkerA{}
} else {
list[n] = &WorkerB{WorkerA{}}
}
}
list[0].Inc()
list[1].Inc()
list[1].Inc()
list[2].Inc()
list[2].Inc()
list[2].Inc()
list[0].Show()
list[1].Show()
list[2].Show()
With the help of the interface array, I could call the corresponding Show method for WorkerA and `WorkerB. Now I would like to add a third method call Addwhich add thex``` between two Workers
func (a *WorkerA) Add(b WorkerA) {
a.x += b.x
}
I find that calling the following will cause an error before list is holding interface not the struct
list[0].Add(list[2])
I look up some idea online, see that reflect may help to solve the problem, here is what I write
func callMethodParam(p interface{}, q interface{}) {
o := reflect.ValueOf(p)
m := reflect.ValueOf(q)
args:=[]reflect.Value{reflect.ValueOf(m)}
o.MethodByName("Add").Call(args)
}
callMethodParam(list[0], list[2])
But this does not seem to work either. Any idea how to make it work? Thanks.
The title of your question sounds like an XY problem but here luckily we know X, do we?
Also the code list[0].Add(list[2]) can't work as it appears in your example because list is declared as a slice of Worker and Worker doesn't have a Add method.
But let's pretend it does. Given that the implementation of Add(b WorkerA) requires accessing a WorkerA's x field, you could change the signature to accept an interface that provides x, and have WorkerA implement that interface:
type XProvider interface {
X() int
}
func (a *WorkerA) X() int {
return a.x
}
func (a *WorkerA) Add(b XProvider) {
a.x += b.X()
}
Then before calling a.Add you use a type assertion to make sure that (the type contained in) a particular instance of Worker also implements XProvider:
if xp, ok := list[2].(XProvider); ok {
list[0].Add(xp)
}
Here's an updated playground

How can I implement the same function for pointers to different structs?

Suppose I have a lot of different structs, but they all share a common field, such as "name". For example:
type foo struct {
name string
someOtherString string
// Other fields
}
type bar struct {
name string
someNumber int
// Other fields
}
Further on in the program, I repeatedly encounter the situation where I get pointers to these structs (so *foo, *bar, etc.) and need to perform operations depending on whether the pointer is nil or not, basically like so:
func workOnName(f *foo) interface{} {
if (f == nil) {
// Do lots of stuff
} else {
// Do lots of other stuff
}
// Do even more stuff
return something
}
This function, which only uses name, is the same across all structs. If these were not pointers, I know I could write a common interface for each struct that returns the name and use that as the type. But with pointers, none of this has worked. Go either complains while compiling, or the nil check doesn't work and Go panics. I haven't found anything smarter than to copy/paste the exact same code for every struct that I have, so basically to implement all the functions:
func (f *foo) workOnName() interface{}
func (b *bar) workOnName() interface{}
func (h *ham) workOnName() interface{}
// And so on...
Is there a way to do this better, i.e. to only implement a simple function (or even better, no function at all) for all my structs and simply write the complicated stuff once, for all the structs?
Edit: Thank you to the answers so far, but simply using an interface of the type:
func (f foo) Name() string {
return f.name
}
for some interface that provides Name() does not work, because the pointer is not recognized as nil. See this playground: https://play.golang.org/p/_d1qiZwnMe_f
You can declare an interface which declares a function returning a name:
type WithName interface {
Name() string
}
In order to implement that interface, you types (foo, bar, etc) need to have that method - not just the field, the method.
func (f foo) Name() string {
return f.name
}
Then, workOnName needs to receive a reference of that interface:
func workOnName(n WithName) interface{} {
if (n == nil || reflect.ValueOf(n).isNil()) {
// Do lots of stuff
} else {
// Do lots of other stuff
}
// Do even more stuff
return something
}
Keep in mind that the parameter n WithName is always treated as a pointer, not an object value.
I think that's the case for reflect.
Something like:
package main
import (
"fmt"
"reflect"
)
func SetFieldX(obj, value interface{}) {
v := reflect.ValueOf(obj).Elem()
if !v.IsValid() {
fmt.Println("obj is nil")
return
}
f := v.FieldByName("X")
if f.IsValid() && f.CanSet() {
f.Set(reflect.ValueOf(value))
}
}
func main() {
st1 := &struct{ X int }{10}
var stNil *struct{}
SetFieldX(st1, 555)
SetFieldX(stNil, "SSS")
fmt.Printf("%v\n%v\n", st1, stNil)
}
https://play.golang.org/p/OddSWT4JkSG
Note that IsValid checks more than just obj==nil but if you really want to distinguish cases of nil pointers and non-struct objects - you are free to implement it.

How can two different types implement the same method in golang using interfaces?

Say I have two structs:
type First struct {
str string
}
type Second struct {
str string
}
And I want both of them to implement interface A:
type A interface {
PrintStr() //print First.str or Second.str
}
It seems redundant to have an implementation for both First and Second structs like so:
func (f First) PrintStr() {
fmt.Print(f.str)
}
func (s Second) PrintStr() {
fmt.Print(s.str)
}
Is there a way I can have one implementation for all the structs implementing interface A? Something like this, but it doesn't seem to work:
func (a A) PrintStr() {
fmt.Print(a.str)
}
Thank you!
No you can't, but you could create a base type and then embed it into your 2 struct, therefore only needing an implementation for the base type:
type WithString struct {
str string
}
type First struct {
WithString
}
type Second struct {
WithString
}
type A interface {
PrintStr() //print First.str or Second.str
}
func (w WithString) PrintStr() {
fmt.Print(w.str)
}
Usage:
a := First{
WithString: WithString{
str: "foo",
},
}
Complete Example on Playground
Embed documentation
If the printing logic depends on the interface but not on the structs themselves, then it is better to move printing to a free function that operates over an interface.
In your case, the PrintStr method is used to print a string which is a member of each structure.
In this case, it means that each structure should implement an interface that returns the necessary string used for printing, and PrintStr becomes a function taking a Printable parameter.
type First struct {
str string
}
type Second struct {
str string
}
type Printable interface {
String() string
}
func (p First) String() string {
return p.str
}
func (p Second) String() string {
return p.str
}
func PrintStr(p Printable) {
fmt.Print(p.String())
}
Your use of the A interface is non-idiomatic because an interface should not depend on the implementation of its functionality.
Instead, with this solution, you can still keep the A interface, but simplify each implementation:
func (f First) PrintStr() {
PrintStr(f)
}
func (s Second) PrintStr() {
PrintStr(s)
}
It is still redundant, but the logic lies in the function that is called from there, limiting the need to do copy-pasting in case of modification of the printing logic.
This pattern is common in the Go standard library, because many useful functions are built upon interfaces which they cannot extend, for example io.Reader.
It is a simple interface with only one method, but it is used thoroughly from many other packages.
If you look at the ioutil.ReadAll function, it could be argued that it could have been implemented as another method of the io.Reader interface, however this keeps readers simpler, concentrating on their single method, while allowing any implementor to use ReadAll for free.
Maybe not the best way to solve your problem, but you could use a wrapper in order to avoid "implementing" the function twice, something like this:
type First struct {
str StringWrapper
}
type Second struct {
str StringWrapper
}
type StringWrapper struct {
str string
}
func (f StringWrapper) PrintStr() {
fmt.Print(f.str)
}
func main() {
var a First = First{str:StringWrapper{str: "aaa"}};
a.str.PrintStr();
}
Why don't you just leave that function out of the interface and pass type A as a parameter?
type A interface {}
type First struct {
str string
}
type Second struct {
str string
}
func PrintStr(a A) {
fmt.Print(a.str)
}

Does Go support Inheritence?

I have heard a lot of people talk about Go, and how it does not support inheritance. Until actually using the language, I just went along with the crowd and listened to the hear say. After a little messing about with the language, getting to grips with the basics. I came across this scenario:
package main
type Thing struct {
Name string
Age int
}
type UglyPerson struct {
Person
WonkyTeeth bool
}
type Person struct {
Thing
}
type Cat struct {
Thing
}
func (this *Cat) SetAge(age int){
this.Thing.SetAge(age)
}
func (this *Cat GetAge(){
return this.Thing.GetAge() * 7
}
func (this *UglyPerson) GetWonkyTeeth() bool {
return this.WonkyTeeth
}
func (this *UglyPerson) SetWonkyTeeth(wonkyTeeth bool) {
this.WonkyTeeth = wonkyTeeth
}
func (this *Thing) GetAge() int {
return this.Age
}
func (this *Thing) GetName() string {
return this.Name
}
func (this *Thing) SetAge(age int) {
this.Age = age
}
func (this *Thing) SetName(name string) {
this.Name = name
}
now, what this does it composes the Person and Cat Structs, from the Thing Struct. By doing so, not only does the Person and Cat struct share the same Fields as the Thing Struct, but also, through composition, the methods of Thing are also shared. Is this not inheritance? Also by implenting an interface as such:
type thing interface {
GetName() string
SetName(name string)
SetAge(age int)
}
All three Structs are now joined or should I say, can be used in a homogenous fashion, such as an array of "thing".
So, I lay it on you, is this not inheritance?
Edit
Added a new derived Struct called "Ugly person" and Overridden the SetAge method for Cat.
It is inheritance but probably not the sort of inheritance you are probably after. Your example look promising b/c Person and Cat are behaviorally and structurally equal to each other modulo the type names.
As soon as you'd attempt to use this "inheritance" to 'extend' some base type with, for example added fields, you'll find that the receiver of the "base class" is always the base class, never the extended one. IOW, you cannot achieve structurally polymorphous type hierarchy.
OTOH, Go supports purely behavioral inheritance via interfaces. Embedding one interface into another does create an inheritance tree.
package main
import "fmt"
type Thing struct {
Name string
Age int
}
func (t *Thing) me() {
fmt.Printf("I am a %T.\n", t)
}
type Person struct {
Thing
}
func (p *Person) Iam() {
fmt.Printf("I am a %T.\n", p)
}
type Cat struct {
Thing
}
func (c *Cat) Iam() {
fmt.Printf("I am a %T.\n", c)
}
func main() {
var p Person
var c Cat
p.me()
p.Iam()
c.me()
c.Iam()
}
It's called composition. Methods of Person or Cat have no direct access to the fields of Thing. Also if e.g. Cat implements an own SetAge() and you want to call the one of Thing you would have to call myCat.Thing.SetAge(42) instead of myCat.SetAge(42).
Since you mentioned C#, try to do this in go. Method calls can't be made virtual in Go (except through interfaces).
// this is C#, not go
public class Thing
{
public virtual string Name {get; set;}
public virtual int Age {get; set;}
}
public class Person : Thing {}
public class Cat : Thing
{
public override int Age
{
get
{
return base.Age * 7; //age in cat's years
}
}
}
and call it like this:
Thing t = new Cat() {Name="Tom", Age=5}; // a Cat object is assigned
// to a Thing variable
Console.WriteLine(t.Age); // outputs 35.
// t.Age refers to Cat's implementation
// of Age, not Thing's. Notice how Age is virtual
// in Thing and overridden in Cat

Resources