Methods dispatch using interface in Go - go

How is actually methods in Go get dispatched if we use interface, static(compile time) or dynamic(run time). Let consider this code:
package main
import "fmt"
type ICat interface {
Meow()
Walk()
Run()
}
func NewCat(name string) ICat {
return &cat{
name:name,
}
}
type cat struct {
name string
}
func (c *cat) Meow() {
fmt.Print("Meowwwwwwwww")
}
func (c *cat) Walk() {
fmt.Print("Walk")
}
func (c *cat) Run() {
fmt.Print("Run")
}
type IAnimal interface{
DoSound()
}
type animal struct {
cat ICat
}
func New() IAnimal {
return &animal{
cat:NewCat("bobby"),
}
}
func (a *animal) DoSound() {
a.cat.Meow()
}
func main() {
i := New()
i.DoSound()
}
Go Playground: https://play.golang.org/p/RzipDT6FAC9
How actually those methods defined in those interface got dispatched?, I use this style of development to implement interface segregation and separation of concern between data and behaviour. My other concern is the perf. Some said it's statically dispatched at compile time, while other said it's dynamically dispatched at run time.

We cannot know at compile time what the dynamic type of an interface value will be, A call through an interface must use dynamic dispatch. Instead of a direct call, the compiler must generate code to obtain the address of the method from the type descriptor, then make an indirect call to that address.

Related

Testing my interface in golang with mocks. Specifically test 1 function that calls a sibling function

Let's say I have this code and I want to create a test for Foo()
The important part it Foo makes a call to Bar
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
}
func NewMyStruct() MyInterface{
return &MyStruct{}
}
func (m *MyStruct) Foo() error {
// do something
m.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
Is it possible to create a test for this where I can mock the behaviour of Bar before I run Foo? or am I doing something fundamentally wrong?
I can see that if I extracted Bar into its own service I would mock it that way but that also doesn't feel right.
Any insights or links to documentation would be great.
You should be able to achieve what you need with a couple of changes. First, let me present the code and then I'll walk you through all of the relevant changes.
main.go file
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
DS MyInterface
}
// here you've to depend upon an interface and return a pointer to a struct
func NewMyStruct(ds MyInterface) *MyStruct {
return &MyStruct{
DS: ds,
}
}
func (m *MyStruct) Foo() error {
// do something
m.DS.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
func main() {}
Here, I changed a couple of things in order to be able to successfully mock our dependencies. Let me recap them:
The MyStruct has a dependency of type MyInterface
The function NewMyStruct accepts the interface as parameter and returns a pointer to the MyStruct struct
In the Foo method, we're going to rely on the DS field of our pointer receiver type instance
Now, let's switch to the test file.
main_test.go file
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// 1. declare mock
type myStructMock struct {
mock.Mock
}
// 2. implement the interface
func (m *myStructMock) Foo() error {
args := m.Called()
return args.Error(0)
}
func (m *myStructMock) Bar() error {
args := m.Called()
return args.Error(0)
}
func TestFoo(t *testing.T) {
// 3. instantiate/setup mock
myStructMock := new(myStructMock)
myStructMock.On("Bar").Return(nil).Times(1)
sut := NewMyStruct(myStructMock)
err := sut.Foo()
// 4. check that all expectations were met on the mock
assert.Nil(t, err)
assert.True(t, myStructMock.AssertExpectations(t))
}
Here, I found it best to add comments within the code to give you a chronological order of what's going on. The idea is that the real system tested (e.g. the sut variable) is relying on mock instead of actual implementations. Thanks to the method Times, we make sure that the Bar method is called once.
I always used this approach when it comes to testing production code and I find it pretty flexible and amazing!
Let me know if this helps you or if you still need something else, thanks!

How to implement two interfaces with same method name and different arguments

I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:
type InterfaceA interface {
Init()
}
type InterfaceB interface {
Init(name string)
}
type Implementer struct {} // Wants to implement A and B
func (i Implementer) Init() {}
func (i Implementer) Init(name string) {} // Compiler complains
It says "Method redeclared". How can one struct implement both interfaces?
As already answered, this is not possible since Golang does not (and probably will not) support method overloading.
Look at Golang FAQ:
Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
It is not possible.
In go you must have a single method signature.
You should rename one method.
The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in go.
package main
import (
"fmt"
"strconv"
)
type SomeData struct {
data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
String() string
Set(data string)
}
func (s *SomeData)String() string {
return s.data
}
func (s *SomeData)Set(data string) {
s.data = data
}
// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
return func(s *SomeData) {
s.Set(data)
}
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
s := new(SomeData)
for _, o := range options {
o(s)
}
return s
}
//********************
type SomeOtherData struct {
data string
i int
}
type SomeOtherInterface interface {
String() string
Set(data string)
}
func (s *SomeOtherData)String() string {
return s.data + " " + strconv.Itoa(s.i)
}
func (s *SomeOtherData)Set(data string) {
s.data = data
}
func SetOtherDataOption(data string) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.Set(data)
}
}
func SetOtherIntOption(i int) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.i = i
}
}
// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
s := new(SomeOtherData)
for _, o := range options {
o(s)
}
return s
}
//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
fmt.Println(si) // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}
func main() {
someData := NewSomeData(SetDataOption("Optional constructor dep"))
someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
HandleData(someData) // calls SomeData.String()
HandleData(someOtherData) // calls SomeOtherData.String()
someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
HandleData(someOtherData) // calls SomeData.String() because there is a SomeData in the someOtherData variable.
}

How to define an interface using another interface

In Go, how to define an interface using another interface?
Here is an example:
package main
import (
"fmt"
)
// Interfaces
type Message interface {
Read() string
}
type MessageReader interface {
ReceiveMessages([]Message)
}
// Structs
type SQSMessage struct {
Content string
}
type SQSMessageReader struct {
Name string
}
// Implements
func (reader *SQSMessageReader) ReceiveMessages([]SQSMessage) {
}
func (msg *SQSMessage) Read() string {
return msg.Content
}
// A function needs a reader interface
func FuncNeedsReader(MessageReader) {
fmt.Println("get reader")
}
func main() {
var reader SQSMessageReader
FuncNeedsReader(reader)
}
I got error:
./prog.go:40:17: cannot use reader (type SQSMessageReader) as type MessageReader in argument to FuncNeedsReader:
SQSMessageReader does not implement MessageReader (wrong type for ReceiveMessages method)
have ReceiveMessages([]SQSMessage)
want ReceiveMessages([]Message)
Do anyone know if this design is conflicting with Go's design?
I know we have "accept interfaces, return structs"
So I also tried https://play.golang.org/p/qdGaKRYAqw7, but still fail with similar error.
I see two problems here.
First:
You have defined your MessageReader interface as:
type MessageReader interface {
ReceiveMessages([]Message)
}
But you have defined your ReceiveMessages method on SQSMessageReader like this:
func (reader *SQSMessageReader) ReceiveMessages([]SQSMessage) {
}
Because it takes an []SQSMessage parameter rather than []Message, it does not implement the MessageReader interface. You would need to write:
func (reader *SQSMessageReader) ReceiveMessages([]Message) {
}
Second:
You have written:
func main() {
var reader SQSMessageReader
FuncNeedsReader(reader)
}
But ReceiveMessages has a pointer receiver (func (reader *SQSMessageReader) ReceiveMessages...), so you would need:
func main() {
var reader SQSMessageReader
FuncNeedsReader(&reader)
}
With these two changes, your code builds without errors.

Effectively wrapping public sdk types in golang

I am using pagerduty go sdk to do a bunch of api requests.
Particularly I am making use of
func NewClient(authToken string) *Client
to create a new Client type. I want to add some utility functions to my own work to *Client. I tried doing this:
type BetterPdClient *pagerduty.Client
func NewClient(auth string) BetterPdClient {
return pagerduty.NewClient(auth)
}
func (b *BetterPdClient) DoSomething() {
b.GetIncident(....)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
pd_client.DoSomething()
}
But I get the following error:
invalid receiver type *BetterPdClient (BetterPdClient is a pointer type)
I understand that DoSomething() is expecting a pointer as caller. Only other way I could think of is sending the ptr as a function argument:
func NewClient(auth string) *pagerduty.Client {
return pagerduty.NewClient(auth)
}
func DoSomething(cl *pagerduty.Client) {
fmt.Println(cl)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
DoSomething(pd_client)
}
Is there a better way?
Declaring a type as a pointer to another type is almost never what you want because Go doesn't allow you to add methods to that new type, nor to the pointer of that type as you've already figured out yourself. This one doesn't compile either:
type T struct{}
type P *T
func (P) M() {}
If you want to "extend" a type without "hiding" it's existing functionality your best bet is to embed it in a struct.
type T struct{
// ...
}
func (T) M() {}
type U struct {
*T
}
func NewU() *U {
return &U{&T{}}
}
func (U) N() {}
func main() {
u := NewU()
u.M()
u.N()
}
And what I mean by "hiding existing functionality" is that when you define a new type in terms of another, already existing type, your new type will not get direct access to the methods of the existing type. All you're doing is just saying that your new type should have the same structure as the already existing type. Although it's worth pointing out that this property gives you the ability to convert one type to the other...
type T struct{
// ...
}
func (T) M() {}
type U T
func NewU() *U {
return &U{}
}
func (U) N() {}
func main() {
u := NewU()
u.M() // compile error
u.N()
// convert *U to *T and then call M
(*T)(u).M()
}

golang: how is "func() interface {}" and "func() *MyStruct" incompatible types?

Suppose I have code, where a function accepts another one as an argument:
type Person struct {
Name string
}
func personBuilder() * Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback func() interface {}){
fmt.Print(callback());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This results in error cannot use personBuilder (type func() *Person) as type func() interface {} in function argument. If I change personBuilder return type to interface{}, it works, but in real project I'm working on I want to have a concrete type for clear design and TDD purposes.
Does Go support such method signature generalization? What are the workarounds, if you could not change the personBuilder part (e.g. you have a lot parameterless functions that return different type of struct, and you want to build a consumer function that accepts any of those builders as argument)?
One workaround is to define an inline function that calls personBuilder.
printRetrievedItem(func() interface{} {return personBuilder()});
Playground
You can create an interface with a method that returns an interface{}:
type Thinger interface {
Thing() interface{}
}
func (p *Person) Thing() interface{} {
return p
}
func printRetrievedItem(t Thinger){
fmt.Print(t.Thing());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This is just an example, please use a better name!
To answer your question, fun() A is not a func() interface{}, for the same reason that []A is not an []interface{}. It's explained very well in the go wiki.
Either do a wrapper like #GrzegorzŻur suggested or define your own interface and make your xxxxBuilder return it:
type Namer interface {
Name() string
}
type Person struct {
name string
}
func (p *Person) Name() string {
return p.name
}
func personBuilder() Namer {
return &Person{name: "John"}
}
func printRetrievedItem(callback func() Namer) {
fmt.Printf("%T: %v", callback(), callback().Name())
}
You can use pkg reflect for this. (Note however that the solution of #OneOfOne is more idiomatic).
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
}
func personBuilder() *Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback interface{}) {
vals := reflect.ValueOf(callback).Call([]reflect.Value{})
fmt.Println(vals[0].Interface())
}
func main() {
printRetrievedItem(personBuilder) // &{John}
printRetrievedItem(func() string { return "hello" }) // hello
}
Here's an example in the playground.

Resources