How to implement two interfaces with same method name and different arguments

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?

Upvotes: 4

Views: 2932

Answers (4)

David Reynolds
David Reynolds

Reputation: 61

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

Upvotes: 2

Asteriskdev
Asteriskdev

Reputation: 102

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

Upvotes: 0

Suyash Medhavi
Suyash Medhavi

Reputation: 1238

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.

Upvotes: 6

Tiago Peczenyj
Tiago Peczenyj

Reputation: 4623

It is not possible.

In go you must have a single method signature.

You should rename one method.

Upvotes: 3

Related Questions