khanhtc's blog

Type embedding not inheritance

Since we don’t have classes in go, you can say struct will do a job to make objects. So how 4 principles of object-oriented programming represent in Golang? In this post, we will discuss the principle of OOP that make Golang better than others object-oriented programming language: inheritance.

A simple question, how does Golang represent inheritance principle even if it doesn’t have extends? We can easily find out the answer to this question: embedding type

type Parent struct {
    ...
}

type Child struct {
    Parent
}

Using the above code snippet, class Child can use all Parent’s properties and methods directly, just like inheritance right? But with me, it’s better than inheritance! Everyone who familiar with OOP thinking know about composition over inheritance principle, which we design objects that are simplified by identifying system object behaviors in separate interfaces instead of creating a hierarchical relationship to distribute behaviors among business-domain classes via inheritance.

The key to this design principle is that we implement a has-a relationship in classes instead of an is-a relationship. Embedding is a representation of a has-a relationship, just embed what we want where we want it!

On the other hand, the interesting part is that we can embed as much as we want (not like inheritance, we can only extend one class due to the truth that we can only answer is-a question once).

type Men struct {}
func (m *Men) drink() string { return "beer" }

type Women struct {}
func (w *Women) drink() string { return "wine" }

type Child struct {
    Man
    Women
}
func (c *Child) drink() string { return "coke" }

Like the above example, we can embed as much as we want! If the embedded classes lead us to the diamond problem, just implement that method to point out which implementation you want the compiler to use in that case.