1

Is there exists some trick to implement virtual functions behaviour in go ? I have the following example.

package main

import "fmt"

type A struct {
}

type B struct {
*A
}

func (this *A) Do() {
    fmt.Println("IM DO")
    this.DoVirtual()
}

func (this *A) DoVirtual() {
    fmt.Println("IM DoVirtual Default implementation")
}

func (this *B) DoVirtual() {
    fmt.Println("IM DoVirtual B implementation")
}

func main() {
    a := &A{}
    a.Do()
    fmt.Println("----")
    b := &B{}
    b.DoVirtual()
    b.Do() // How to make here B.DoVirtual call
}

And the last Do() call uses also default DoVirtual implementation what is actually not was I want. The reason why is it so is go lang iheritance model : this *B and this *A are different pointers in this case, but I wonder is it possible to make some simulation of such behaviour that DoVirtual in last call will be used from B class.

Oleg
  • 3,080
  • 3
  • 40
  • 51
  • 1
    Some questions+answers which show how to circumvent the lack of inheritance: 1. [Go: Ensuring embedded structs implement interface without introducing ambiguity](http://stackoverflow.com/questions/36710259/go-ensuring-embedded-structs-implement-interface-without-introducing-ambiguity), 2. [How to arbitrarily extend an “object” in Go](http://stackoverflow.com/questions/34261933/how-to-arbitrarily-extend-an-object-in-go), 3. [Go embedded struct call child method instead parent method](http://stackoverflow.com/questions/29390736/go-embedded-struct-call-child-method-instead-parent-method) – icza Apr 27 '16 at 08:49
  • All such answers explains why it is not possible on go - why is it I know. I don't know how the other implement such type of pattern - or what pattern is similar to it but has a reasonable implementation on go . @Jiang YD - has suggested to use reflection for such pattern - it is actually the answer to my question - but in real life i would not use such type of solution (it hides the problem from a reader) and make some refactoring to just avoid such pattern. – Oleg Apr 27 '16 at 10:24
  • 2
    You have to store the "parent" if you want to call a method that is potentially overridden by parent. The linked answers show example of this. But try not to solve your problem with inheritance and virtual functions. Try to think in composition. – icza Apr 27 '16 at 10:27

2 Answers2

3

By the time the compiler has selected func (this *A) Do() { the enclosing B is gone, no longer accessible. Go does not support the is-a construct, only the has-a (composition). If one implements a func (this *B) Do() { it will supersede the Do() on *A. Of course, that's not really what you are wanting.

I think the best explanation of the implementation and motivation is here Less is exponentially more from Rob Pike.

foo
  • 701
  • 4
  • 8
2

my simple simulation, you can improve it with some reflect, code generation or even RPC. the main idea is add a virtual method table, and do dispatch yourself, just like c++ does.

package main

import "fmt"

type A struct {
virFunDispatcher func(funAndParams ... interface{})
}

func newA() *A{
    return &A{func(funAndParams ... interface{}){
        fun := funAndParams[0].(string)
        switch(fun){
            case "DoVirtual":
                fmt.Println("IM DoVirtual Default implementation")
        }
    }}
}

type B struct {
*A
}


func newB() *B{
    a := A{func(funAndParams ... interface{}){
        fun := funAndParams[0].(string)
        switch(fun){
            case "DoVirtual":
                fmt.Println("IM DoVirtual B implementation")
        }
    }}
    return &B{&a}
}

func (this *A) Do() {
    fmt.Println("IM DO")
    this.virFunDispatcher("DoVirtual")
}

func (this *A) DoVirtual() {
    fmt.Println("IM DoVirtual Default implementation")
}

func (this *B) DoVirtual() {
    fmt.Println("IM DoVirtual B implementation")
}

func main() {
    a := newA()
    a.Do()
    fmt.Println("----")
    b := newB()
    b.DoVirtual()
    b.Do() // How to make here B.DoVirtual call
}

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

Jiang YD
  • 3,205
  • 1
  • 14
  • 20