14

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 ?

3
  • 2
    There is absolutely nothing to deal with: Any type which has a method Do() string implements both interfaces A.Doer and B.Doer. Commented Jan 24, 2015 at 10:33
  • I think you are right @Volker, there is no fix for that, and this situation can occur in any language that uses interfaces (java for example). Commented Jan 24, 2015 at 11:27
  • Very valid question. I had the same thought. Thanks for asking here in the forum @SalahEddineTaouririt Commented Sep 2, 2022 at 9:18

2 Answers 2

10

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().

Sign up to request clarification or add additional context in comments.

2 Comments

but the logic implemented in the Do method to satisfy A is completely different from the one in B.
Thanks @VonC, me too, I added more code to clarify the issue.
4

By definition, you are satisfying both:

A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without having to modify existing code. It enables a kind of structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, lightweight feel.

So, with that in mind, you can either:

a) Add comments to the the interface methods defining your expectations on the logic (see the io.Reader interface or a good example)

b) Add an extra method called ImplementsDoerA and ImplementsDoerB on the interfaces (also mentioned in the FAQ).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.