Noobie
Noobie

Reputation: 581

Explain go interface definition in go wiki

I understand a bit a go and to certain extend understand interface as well(like how I do ducktyping in ruby) But reading the interface definition https://github.com/golang/go/wiki/CodeReviewComments

I'm clueless what is trying to convey.

1st: I did not understood the comment.

Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values.

2nd: I do not understand this

Do not define interfaces on the implementor side of an API "for mocking"; instead, design the API so that it can be tested using the public API of the real implementation.

3rd: I do not understand the example

Do not define interfaces before they are used: without a realistic example of usage, it is too difficult to see whether an interface is even necessary, let alone what methods it ought to contain.


package consumer  // consumer.go

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { ..... }


package consumer // consumer_test.go

type fakeThinger struct{ … }
func (t fakeThinger) Thing() bool { … }
if Foo(fakeThinger{…}) == "x" { ... }
// DO NOT DO IT!!!
package producer

type Thinger interface { Thing() bool }

type defaultThinger struct{ … }
func (t defaultThinger) Thing() bool { … }

func NewThinger() Thinger { return defaultThinger{ … } }
package producer

type Thinger struct{ … }
func (t Thinger) Thing() bool { … }

func NewThinger() Thinger { return Thinger{ … } }

Can someone explain in plain and easier word the 3 things above.

Upvotes: 3

Views: 1082

Answers (1)

Kenny Grant
Kenny Grant

Reputation: 9633

Forget analogies with other languages for the moment. Think of an interface like a contract - a set of requirements for the function that uses it.

Say I define a function MakeNoise which needs to know the sound of the thing passed in, but otherwise doesn't care about it. Code below is all together, but imagine this in two separate packages - one for concrete types and one for MakeNoise.

The MakeNoise function could take a specific type, but this limits it somewhat, might make testing harder etc, so often you might want it instead to define what it needs the type to do - in this case it just needs something with a Sound() method to call, other than that it doesn't care.

Now on the Cat/Dog side, you might not care about MakeNoise, or even know about it yet, your animals should be defined separately and not care about any interfaces they conform with - those interfaces might not even have been written yet.

So the Wiki is just saying that whoever writes MakeNoise should care about what it requires and put that in an interface, but whoever writes Cat/Dog should not care, and the interface should sit with MakeNoise, not with Cat/Dog. This means later someone might come and write a Giraffe in another package, and it can still be used with MakeNoise.

The interface is a requirement, not a promise.

https://play.golang.org/p/4r1wiXokKMb

// Here are some types which share one function. 
// They might have other functions too
package main

type Cat struct {}
func (d Cat) Sound() string {
    return "miao"
}

type Dog struct {}
func (d Dog) Sound() string {
    return "woof"
}

func main() {
    cat := Cat{}
    dog := Dog{}

    MakeNoise(cat)
    MakeNoise(dog)
}


// Sounder is the requirement for MakeNoise, so it lives with it.
// perhaps in a package together which knows nothing of cats and dogs.
type Sounder interface {
    Sound() string
}

// MakeNoise prints the sound of the thing
// it only cares the thing makes a Sound
func MakeNoise(thing Sounder) {
    println(thing.Sound())
}

Upvotes: 3

Related Questions