If anything, C++ is less object-oriented than Go, and more oriented towards abstract data types (which C++ programmers call “concepts”).
Go makes classic inheritance impossible, it is a bit more than discouraging it.
(0) Embed base structs.
(1) Implement non-overridden methods as redirected calls to base struct methods.
(2) Implement overridden method calls however you wish.
What Go doesn't make possible is tying inheritance to subtyping, like Java and C++ do. And this is a very good thing.
What you described is not inheritance. If you pass your "inherited" type to a function that expect the "parent" type it will not compile. There is no inheritance in Go, and you cannot roll you own.
> What Go doesn't make possible is tying inheritance to subtyping
There is no subtying whatsoever in Go to begin with. There is no point in "inheritance" if it is not polymorphic. What you just did is create a new type. that is not inheritance in a statically typed language.
That is called “subtyping”, not “inheritance”. Java and C++ happen to conflate the two concepts, but it's perfectly possible to keep them separate.
> There is no subtying whatsoever in Go to begin with.
A struct is a subtype of every interface its methods are compatible with.
I never said that struct embedding creates a subtype. I said that it can be used to emulate inheritance (subclassing). Inheritance and subtyping are very different things, and the fact languages like Java and C++ conflate them actually creates several problems. See:
[0] http://www.cs.utexas.edu/~wcook/papers/InheritanceSubtyping9...
I haven't put it into practice, but it seems like this should give callers enough flexibility to pass in whatever they like.
You can have `datastore.New() Datastore`, which returns one of the implementations, or you can have `datastore.NewMySQLStore, datastore.NewInMemStore()`. Now you need a different method for each implementation.
Also be careful with returning concrete type, you can run into this issue: https://play.golang.org/p/WHAW1X6elS
This is a tricky concept until you learn that interfaces are reference types.
Here's a simplified version of the previous example that illustrates this concept: https://play.golang.org/p/pODBgaHXq5
First: I took a brief look through this, and I didn't see anything that jumped out as wrong. It's a pretty comprehensive document, especially for someone who says they're just starting out, so kudos to James for writing it!
That said, from my experience in teaching Go classes and workshops for beginners, comparing embedding to inheritance is usually a bad idea. It's not that there aren't similarities, but in my experience it prompts new Go programmers to write unidiomatic Go code when they think of embedding in that way. They end up embedded structs the way they'd use inheritance in object-oriented languages, and since Go isn't really intended as an object-oriented language, it makes for unidiomatic code.
The main use cases of inheritance in OOP are accomplished by interfaces in Go, not struct embedding. But at the same time, the main benefits of embedding come from embedding interfaces - embedding structs is almost an afterthought in the language. In fact, I tend to advise people against embedding structs altogether. There are a few cases where it's worthwhile to embed structs, but the use case for embedding interfaces is much more powerful.
My advice for Go beginners: use interfaces more than you think you need to, and forget that struct embedding is even possible. This rule of thumb helps to write more idiomatic Go code when you're just getting started, before you have a feel for what that really means.