Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement two different interfaces with the same method signature

Tags:

interface

go

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 ?

like image 971
Salah Eddine Taouririt Avatar asked Jan 24 '15 10:01

Salah Eddine Taouririt


People also ask

CAN 2 interfaces have the same method name?

The implementation of interface's members will be given by the class who implements the interface implicitly or explicitly. C# allows the implementation of multiple interfaces with the same method name.

Can methods have same signature?

Method signature is used during the method creation. Two Methods cannot have same method signature. Methods can have same method name, and this process called method overloading.

Can you implement 2 interfaces?

Yes, a class can implement multiple interfaces. Each interface provides contract for some sort of behavior.

Which is the correct way to implement from multiple interfaces?

However, it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To implement multiple interfaces, separate them with a comma (see example below).


2 Answers

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

like image 124
VonC Avatar answered Sep 22 '22 15:09

VonC


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

like image 33
iccananea Avatar answered Sep 25 '22 15:09

iccananea