1

I'm trying to reach this way of polymorphism in GO

type Discoverer interface {
    Discover() string
}

type A struct {
}

func (obj A) GetTest() string {
    return "im in A"
}

type B struct {
    A
}

func (obj B) GetTest() string {
    return "im in B"
}

func (obj A) Discover() string {
    return obj.GetTest()
}

func main() {
    a := A{}
    b := B{}

    fmt.Println(a.Discover())
    fmt.Println(b.Discover())
}

Now I'm getting in output

im in A
im in A

So, my question is: It is possible to see in output

im in A
im in B

Without "override" Discover of B?

func (obj B) Discover() string {
    return obj.GetTest()
}

Why? I've alot of small methods in struct (as classes) and Discover pretty the same for all structs, so I want to avoid copy&paste Discover in each struct(class)

go playground https://play.golang.org/p/nYc2hc3UbG

Thanks in advance!

  • 1
    There is no inheritance (and no polymorphism) in Go. Some related / possible duplicates: [one](http://stackoverflow.com/questions/21251242/is-it-possible-to-call-overridden-method-from-parent-struct-in-golang), [two](http://stackoverflow.com/questions/30622605/can-embedded-struct-method-have-knowledge-of-parent-child), [three](http://stackoverflow.com/questions/29390736/go-embedded-struct-call-child-method-instead-parent-method), [four](http://stackoverflow.com/questions/29144622/what-is-the-idiomatic-way-in-go-to-create-a-complex-hierarchy-of-structs). – icza May 16 '16 at 19:03

2 Answers2

7

No. You're embedding A in B. B has no definition for Discover, therefor the version on A is always invoked. That method has a receiver of type A and A has no awareness of B or the fact that it's embedded in B. Therefor A can only call it's own version of GetTest().

The only reason B satisfies the discover interface is because it has A embedded. It implements it indirectly. If you want the functionality on B, you have to define it on B. This isn't polymorphism at all, it's composition. B isn't an A, B has an A. If you want polymorphism, you use interfaces and implement them. B is a discoverable, but only because it has an A.

I would assume this is just for the example but you actually have no reason at all to even have this Discovery method. Your interface should just require GetTest instead. Don't confuse embedding with inheritance. There is no inheritance in Go. If you want polymorphic behavior you achieve it by implementing interfaces and you can't cut corners like this because the relationship between an embedded type and the embeddor is not one of inheritance, there is no base class or "overrides".

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
  • Okay, that's what I'm trying to implement, may be you can enlight me how I can do this in GO? https://play.golang.org/p/sqF9nxQBBW It's class factory which returns object depends on user input (config file really), then I must fill structure myStruct and save it to database. – How to change username May 16 '16 at 19:04
2

To add to @evanmcdonnal's point, embedding is neither inheritance nor polymorphism. Inheritance just happens to be a convenience such that you may get the implementation of an interface for free but in Go, its explicit. Embedding may seem like inheritance but is not, as @evanmcdonnal has pointed out.

Rather, you should separate the concepts polymorphism from inheritance and embedding and inheritance. The comparisons do not carry over from most object oriented languages. As an example, below would be an implementation of polymorphism. Notice that Discover takes an interface and A and B implements the interface, making the function itself polymorphic.

package main

import "fmt"

type A struct{}
type B struct{}

type Test interface{
    GetTest() string
}

func (a *A) GetTest() string {
    return "i am in A"
}

func (b *B) GetTest() string {
    return "i am in B"
}

func Discover(t Test) string {
    return t.GetTest()
}

func main() {
    a := &A{}
    b := &B{}

    fmt.Println(Discover(a))
    fmt.Println(Discover(b))
}
Will C
  • 1,750
  • 10
  • 20
  • Please look for comment in @evanmcdonnal answer, there's example what I'm trying to do. – How to change username May 16 '16 at 19:11
  • 2
    I would refrain from using names like `BaseClass` and `DerivedClass` in the code. It makes it much more confusing since there are no such thing as classes and inheritance in Go. If you break your implementation of the different `GetValue` methods, you can compose a larger `struct` with them. This would be one way that can mimic your desired behavior. – Will C May 16 '16 at 20:14