32

I have the following:

type Base struct {

}

func(base *Base) Get() string {
    return "base"
}

func(base *Base) GetName() string {
    return base.Get()
}

I want to define a new type with a new implementation of Get() so that I can use the new type in place of Base and where GetName() is called it calls the new Get() implementation . If I were using Java I would inherit Base and override Get(). How should I achieve this in Go? I want to avoid breaking changes if possible, so existing consumers of Base do not need to be changed.

My first stab at this looks like..

type Sub struct {
    Base
}

func(sub *Sub) Get() string {
    return "Sub"
}

..which doesn't work. My brain isn't wired for Go yet clearly.

Myles McDonnell
  • 12,943
  • 17
  • 66
  • 116
  • 2
    Possible duplicate of [is it possible to call overridden method from parent struct in golang?](http://stackoverflow.com/questions/21251242/is-it-possible-to-call-overridden-method-from-parent-struct-in-golang) – Vadyus Jun 30 '16 at 13:20
  • 1
    Go doesn't have inheritance, nor does it have generics. If something is expecting the type `Base`, you can't provide that with a different type. – JimB Jun 30 '16 at 13:21
  • 1
    I would like to recommend [this post](https://medium.com/random-go-tips/method-overriding-680cfd51ce40) to you. – flycash May 28 '20 at 08:19

3 Answers3

13

Interfaces are named collections of method signatures:
see: https://gobyexample.com/interfaces
and: http://www.golangbootcamp.com/book/interfaces
so it is better not to use in such OOP way.


what you asking is not Golang idiomatic but possible (2 ways):

this is what you need (working sample code):

package main

import "fmt"

type Base struct {
}

func (base *Base) Get() string {
    return "base"
}

type Getter interface {
    Get() string
}

func (base *Base) GetName(getter Getter) string {
    if g, ok := getter.(Getter); ok {
        return g.Get()
    } else {
        return base.Get()
    }
}

// user code :
type Sub struct {
    Base
}

func (t *Sub) Get() string {
    return "Sub"
}
func (t *Sub) GetName() string {
    return t.Base.GetName(t)
}

func main() {
    userType := Sub{}
    fmt.Println(userType.GetName()) // user string
}

output:

Sub

as you see one initialization code must be done in user code:

func (t *Sub) GetName() string {
    return t.Base.GetName(t)
}

also this works:

package main

import "fmt"

type Getter interface {
    Get() string
}

type Base struct {
    Getter
}

func (base *Base) Get() string {
    return "base"
}

func (base *Base) GetName() string {
    return base.Getter.Get()
}

// user code :
type Sub struct {
    Base
}

func (t *Sub) Get() string {
    return "Sub"
}
func New() *Sub {
    userType := &Sub{}
    userType.Getter = interface{}(userType).(Getter)
    return userType
}

func main() {
    userType := New()
    fmt.Println(userType.GetName()) // user string
}

output:

Sub

as you see one initialization code must be done in user code:

userType.Getter = interface{}(userType).(Getter)
  • 46
    Go is making me cry so much. Decades of progress in coding languages being forgotten. – Kangur Mar 01 '19 at 13:28
  • 1
    What if I include a library that defines Base struct but NO Getter interface. I have no possibility to change library code. So let's assume, we have no interface. Just Base struct we want to "override". Yes yes, I know, Golang has no "overriding, polymorphism etc.", you know, what I mean, just composition. – Hermann Schwarz Jun 06 '20 at 12:50
  • 1
    @Kangur, I think the oposite, we never needed to override methods and we didn't know it! All we really needed was an interface and the implementors. It is really better without it, overriding methods are heavy on the machine, but the interfaces are all calculated in compilation time, no extra memory in runtime is used by the program to decide what method to call. All we need to do is change our culture to start focusing more in interfaces and not use super types – wellsantos May 17 '21 at 20:44
  • 1
    @wellsantos After a few months of writing golang code I agree. I know consider Go to have a very good balance between abstraction concepts and speed of invocation due to binding all methods at compilation time. I like it now, but as you said one have to leave aside or adapt some old approaches. – Kangur Jun 05 '21 at 10:22
  • Possibly noob Go question: what is stopping me from replacing library implementation of some "interface" method with my own local definition? A "duplicate method" linker error or ... ? – Charlie Reitzel Apr 13 '22 at 16:29
  • 2
    @wellsantos There's nothing 'heavy' about inheritance; it's a function pointer in a table. This method of using interfaces with all-or-nothing implementations leads to this exact class of problem, which then is inevitably solved (as suggested several times for this question) by assigning function pointers. Manual structures of function pointers were how we solved this problem decades ago, in C. – shanef22 Jun 08 '22 at 19:38
  • Omg Google engineers are smart, Go is for sure performant, but such hypesters.. – Alexandre Daubricourt Sep 29 '22 at 11:53
  • Can just use `userType.Getter = userType` – Pegasus Nov 10 '22 at 03:24
10

Go is not a "classic" OO language: it doesn't know the concept of classes and inheritance.

However it does contain the very flexible concept of interfaces, with which a lot of aspects of object-orientation can be made available. Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.

An interface defines a set of methods, but these methods do not contain code: they are not implemented (this means they are abstract).

So the way you can achieve to use different type inside the same method is to use interfaces.

Here is simple example to prove it:

package main

import (
    "fmt"
)

type Base struct{}
type Baser interface {
    Get() float32
}

type TypeOne struct {
    value float32
    Base
}

type TypeTwo struct {
    value float32
    Base
}

type TypeThree struct {
    value float32
    Base
}

func (t *TypeOne) Get() float32 {
    return t.value
}

func (t *TypeTwo) Get() float32 {
    return t.value * t.value
}

func (t *TypeThree) Get() float32 {
    return t.value + t.value
}

func main() {
    base := Base{}
    t1 := &TypeOne{1, base}
    t2 := &TypeTwo{2, base}
    t3 := &TypeThree{4, base}

    bases := []Baser{Baser(t1), Baser(t2), Baser(t3)}

    for s, _ := range bases {
        switch bases[s].(type) {
        case *TypeOne:
            fmt.Println("TypeOne")
        case *TypeTwo:
            fmt.Println("TypeTwo")
        case *TypeThree:
            fmt.Println("TypeThree")
        }

        fmt.Printf("The value is:  %f\n", bases[s].Get())
    }   
}

Go Playground

Endre Simo
  • 11,330
  • 2
  • 40
  • 49
  • 29
    I don't think this answers the question. He wanted to instantiate the subclass, call GetName and actually have the subclass method called. This example makes no attempt into tackling that. – Rafael Almeida Jun 21 '17 at 22:26
  • 1
    Where is an overriding the method? You demonstrate different interface implementations. – S2201 Sep 15 '20 at 15:32
  • Go has a concept of inheritance by encapsulating other types. All fields and methods are exposed on the final type, but can be accessed directly as well. – Kangur Jun 05 '21 at 20:34
  • 1
    Why do you encapsulate Base if it's not providing any fields or methods? It could be removed with no side effects. – Kangur Jun 05 '21 at 20:36
7

Here is how you can "override" method and access it also from encapsulating struct:

package main

import (
    "fmt"
)

type Getter interface {
    Get() string
}

type Base struct {
}

type Sub1 struct {
    Base // reuse fields and methods
}

type Sub2 struct {
    Base // reuse fields and methods
}

func(base *Base) Get() string {
    return "getBase" 
}

func(sub1 *Sub1) Get() string {
    return "getSub1" // override base method
}


func(sub1 Sub1) CallOverriden() string {
    return sub1.Get()
}

func(sub1 Sub1) CallBase() string {
    return sub1.Base.Get() // access and expose encapsulated/embedded method
}


func main() {
    var g Getter
    g = &Sub1{}
    
    fmt.Println(g.Get()) // getSub1
    
    g = &Sub2{}
    fmt.Println(g.Get()) // getBase // not-overriden method
    
    fmt.Println(Sub1{}.CallOverriden())
    fmt.Println(Sub1{}.CallBase()) // "base" method can be exposed
}
Kangur
  • 7,823
  • 3
  • 30
  • 32
  • The method works from the outside but not from inside, e.g. for Base's other methods to call `Get` and allows derived/enclosing structs to override that behavior. – jiping-s Jun 28 '21 at 09:28
  • 2
    I believe that's not possible in Golang @jiping-s. `Base`'s other methods specify what they know - Base other methods. They do not know about derived structs unless you specify it explicitly. If you need this method of the base to operate it on different object, then maybe just pass it as a parameter. `func(base *Base) Get(do Doer) string { return do.DoIt() + "base processing" }`. Then you can pass any kind of struct implementing Doer interface (implementing = having method with the same definition as Doer). – Kangur Aug 19 '21 at 14:00