Interface in Go – Implementing Two Interfaces with Same Method Signature

gointerface

Suppose that I have to implement two different interfaces declared in two different packages (in two different separated projects).

I have in the package A

package A

type interface Doer {
    Do() string
}

func FuncA(Doer doer) {
     // Do some logic here using doer.Do() result

     // The Doer interface that doer should implement, 
     // is the A.Doer
}

And in package B

package B

type interface Doer {
    Do() string
}

function FuncB(Doer doer) {
    // some logic using doer.Do() result

     // The Doer interface that doer should implement, 
     // is the B.Doer
}

In my main package

package main

import (
    "path/to/A"
    "path/to/B"
)

type C int

// this method implement both A.Doer and B.Doer but
// the implementation of Do here is the one required by A !
func (c C) Do() string {
    return "C now Imppement both A and B"
}

func main() {
    c := C(0)
    A.FuncA(c)
    B.FuncB(c) // the logic implemented by C.Do method will causes a bug here !
}

How to deal with this situation ?

Best Answer

As the FAQ mentions

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.

In your case, you would satisfy both interfaces.

You can you the can test whether an object (of an interface type) satisfies another interface type A.Doer, by doing:

if _, ok := obj.(A.Doer); ok {
}

The OP adds:

But the logic implemented in the Do method to satisfy A is completely different from the one in B.

Then you need to implement a wrapper around you object:

  • a DoerA, which has your object C as a field, and implement A.Do() in a manner that satisfy how A.Do()is supposed to work
  • a DoerB, which has your same object C as a field, and implement B.Do() in a manner that satisfy how B.Do() is supposed to work

That way, you will know which Doer to pass to a function expecting an A.Doer or a B.Doer.
You won't have to implement a Do() method on your original object C, which would be unable to cope with the different logic of A.Do() and B.Do().

Related Question