4

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?

0

4 Answers 4

6

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.

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

1 Comment

That's terrible! The libraries make the most sense with different signatures, and they're in two different libraries also. This feels like a major obstacle to using interfaces in the way that Go wants me to. But thank you for the explanation!
3

It is not possible.

In go you must have a single method signature.

You should rename one method.

Comments

3

How can one struct implement both interfaces?

Well ... it depends if you're okay putting a wrapper around your "one struct."

If you find it unacceptable to wrap your struct ... then what the other contributors have written is spot on! It's true that Go doesn't permit such method overloading.

However, if you wrap your Implementer type ... then you can implement both interfaces without any problem.

Here is the work-around ...

type InterfaceA interface {
    Init()
}

type InterfaceB interface {
    Init(name string)
}

type Implementer struct{} // Your one struct

type ImpA Implementer     // Wrapped version to implement InterfaceA
type ImpB Implementer     // Wrapped version to implement InterfaceB

func (i ImpA) Init() {}

func (i ImpB) Init(name string) {}

If you go to the playground, you'll find that it runs fine!

Go playground to demonstrate the code above!

Also, it should be noted that elements of this question overlap with another stack overflow question with the following answer ...

Solution to: How to implement two different interfaces with the same method signature

Comments

0

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

2 Comments

You might have missed the point here. The author specifically asked for a solution where method signatures are different
I didn't miss the point. I answered the question and offered an alternative. This question gets asked so often, it may help the OP or anyone who finds the question. You down voting it makes it seem untrustworthy. I think maybe you missed the point of what the down vote is for.

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.