Calling the embedding struct's overloaded method from the embedded struct

Consider this example:

package main

import (
    "fmt"
)

type A struct {}

func (a *A) TheMethod() {
    fmt.Println("TheMethod (A's implementation)")
}

type B struct {
    A
}

func (b *B) TheMethod() {
    fmt.Println("TheMethod (B's implementation)")
}

func (a *A) TheMethodCallingTheMethod() {
    a.TheMethod()
}

func main() {
    foo := B{}
    foo.TheMethodCallingTheMethod()
}

The output is TheMethod (A's implementation) which is sort-of understandable.

However, shouldn’t it ideally be TheMethod (B's implementation)?

The rationale is that B already can transparently see A’s methods. So, why would A’s TheMethodCallingTheMethod (when called from an instance of B) not be able to transparently see that it’s B calling it, not A, and hence, call B’s TheMethod not A’s?

TheMethodCallingTheMethod method belongs to struct A. Try this, for example:

package main
import "fmt"

type A struct{}

func (a *A) MethodOnlyA() {
  fmt.Println("Only in A ")
}

func (a *A) TheMethod() {
  fmt.Println("Method in A")
}

type B struct {
  A
}

func (b *B) MethodOnlyB() {
 fmt.Println("Only in B")
}

func (b *B) TheMethod() {
  fmt.Println("Method in B")
}

  func main() {
    foo := B{}
    foo.MethodOnlyB()
 foo.MethodOnlyA()

 foo.TheMethod()
 foo.TheMethod()

}

Note that heMethod is defined for both structuire and altought in the A case, I explicity say that the receiver is A, if called using foo, then the method in B struct is called

In Go there is an important distinction between Struct Types and Interface Types. What you are trying to do would work with interfaces, since the call to an interface method is dispatched dynamically to the underlying type inside the interface.

But a struct is always just a struct. You cannot cast A to B or B to A. TheMethodCallingTheMethod has a receiver of type A it will never by called on anything but a struct of Type A.
The line foo.TheMethodCallingTheMethod() is just syntax-sugar for the call foo.A.TheMethodCallingTheMethod() which will be determined at compile time (not dynamically at runtime) And so the method will not receive the struct B but only the embedded struct A.

This code makes it probably more clear what is happening:

unwrappedA := foo.A
unwrappedA.TheMethodCallingTheMethod()

So unwrappedA has no reference to it’s parent foo, it does not “know” it is part of a B struct, it could also be part of any other struct or a slice. It is just a memory address and uses static calls determined at compile time.

2 Likes