0

I wonder if is there solution for apply "polymorphism" in embedded functions when one pointing to other. For example I have following interface:

type Client interface {
    Get(string) string
    GetResource() string
}

and default implementation:

type ClientImpl struct {
}

func (c ClientImpl) Get(s string) string {
    return fmt.Sprintf("Impl [%s]", s)
}

func (c ClientImpl) GetResource() string {
    return c.Get("resource") # points to Get
}

And in other implementation (tests for example) I want to replace default Get function with other response but leave GetResource method untouched

type TestImpl struct {
    ClientImpl
}

func (t TestImpl) Get(s string) string {
    return fmt.Sprintf("Test [%s]", s)
}

Override function works when it's called directly but doesn't when called from embedded function. Look output produced from following test case:

c := ClientImpl{}
t := TestImpl{}
fmt.Println("WORKS:")
fmt.Println("Client Get:", c.Get("aaa"))
fmt.Println("Test   Get:", t.Get("aaa"))
fmt.Println("DOSN'T WORK :(")
fmt.Println("Client GetRes:", c.GetResource())
fmt.Println("Test   GetRes:", t.GetResource())

# WORKS:
# Client Get: Impl [aaa]
# Test   Get: Test [aaa]
# DOSN'T WORK :(
# Client GetRes: Impl [resource]
# Test   GetRes: Impl [resource]

How to make last print to output string Test [resource]?

Go Playground example: https://play.golang.org/p/b-vM1_W3oB

4
  • "How to make last print to output string Test [resource]?" No way. Commented Apr 6, 2017 at 9:04
  • Ok so I have to duplicate code or extract Get function from Client interface? Commented Apr 6, 2017 at 9:06
  • 3
    The best advice is: Stop trying to mimic "traditional OOP" with embedding. It just doesn't work out. If you need a test implementation of an interface: Write one. Commented Apr 6, 2017 at 9:13
  • Go features polymorphism via interfaces exclusively. It does not support inheritance or overriding, and embedding is not a way of faking these features. Any time you try to force OOP into Go, you're going to run into problems; you have to write Go as Go, not as any other language. Commented Apr 6, 2017 at 14:56

1 Answer 1

2

In your example, you need to isolate the Get function in its own interface.

Here are two similar ways to do this :

// one way to do this :
type Getter interface {
    Get(string) string
}

type ClientImpl struct {
}

func (c ClientImpl) Get(s string) string {
    return fmt.Sprintf("Impl [%s]", s)
}

type TestImpl struct {
}

func (t TestImpl) Get(s string) string {
    return fmt.Sprintf("Test [%s]", s)
}

// write a bare GetResource function :
func GetResource(c Getter) string {
    return c.Get("resource")
}

https://play.golang.org/p/R2XciBx_yk

// another way : store the "Getter" as a field in a struct
type Getter interface {
    Get(string) string
}

type ProdGetter struct {
}

func (c ProdGetter) Get(s string) string {
    return fmt.Sprintf("Impl [%s]", s)
}

type TestGetter struct {
}

func (t TestGetter) Get(s string) string {
    return fmt.Sprintf("Test [%s]", s)
}

// create a struct, which holds a Getter, and has methods to do stuff with it :
type Client struct {
    Getter
}

func (c *Client) GetResource() string {
    return c.Get("resource")
}

https://play.golang.org/p/ZMI5PlAo4L

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

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.