I'm not sure that's true. I think that Go has much stronger inheritance mechanisms than, say, C# or Java, albeit also more foot-gun friendly.
type Doer interface {
DoIt()
}
type Foo struct {}
type Bar struct { Foo }
func (*Foo) DoIt () {
fmt.Println("Just do it!")
}
func Incite (d Doer) {
d.DoIt()
}
func main () {
b := &Bar{}
Incite(b)
}
One can transparently invoke Foo's DoIt on instances of Bar or, if Bar had its own DoIt defined, it would override that.
Foot-gun wise, of course, if you convert a Bar to a Foo and pass it to something, you no longer get Bar's version of DoIt.
However, anywhere that accepts a Doer accepts a Bar without decomposing it into a Foo, so Incite will invoke Bar's DoIt and, if Bar didn't define a DoIt method, it would still implement Doer via composition of Foo.
One might argue that this is composition not inheritance, but although it's implemented as composition internally, from the outside it appears that Bar isa Doer, even though it doesn't implement DoIt.
Usually, composition would require either forwarding methods which disguise the fact that composition is happening, or for external code to actually access the components directly. Go allows something that looks very much like inheritance.
(I'd also note that, in reality, inheritance is internally implemented as composition. What Go makes explicit is what implicitly happens in C++ or Java anyway.)