1. 4
  1.  

  2. 3

    The struct embedding gives a great deal of power. You can effectively inherit data and methods. And override methods.

    I think the only case where classical polymorphism falls down is having to explicitly reference the embedded type in non-method calls. Method calls proxy just fine though.

    I get that this isn’t “really” an is-a relationship, but it feels close enough to get work done for me.

    package main
    
    type A struct {
        Name string
    }
    
    type B struct {
        A
    }
    
    func who(a A) {
        println("I am", a.Name)
    }
    
    func (a A) whoMethod() {
        println("As a method, I am", a.Name)
    }
    
    func (a A) Shout() {
        println("I AM", a.Name)
    }
    
    func (b B) Shout() {
        // We also have access to the embedded type's implementation if we want it
        // via b.A.Shout
        println("I SHOUT MY NAME", b.Name)
    }
    
    func main() {
        a := A{"alice"}
        b := B{A{"bob"}}
    
        a.whoMethod()
        b.whoMethod() // Calls the inherited method
        a.Shout()
        b.Shout() // Calls the overridden method
        who(a)
        who(b.A) // who(b) will fail with a compile-time error
    }