Image

Golang: composition over inheritance.

Introduction

One of the first things new Go programmers hear is:

"Go prefers composition over inheritance."

If you come from Java, C++, or C#, this may sound strange because those languages rely heavily on inheritance. Let's explore what this means and why Go was designed this way.


What is Inheritance?

In object-oriented languages, a class can inherit from another class.

Animal
 ├── Dog
 ├── Cat
 └── Bird

The parent class contains common functionality that every child receives automatically.

class Animal {

    void Eat() {
        System.out.println("Eating");
    }

}

class Dog extends Animal {

    void Bark() {
        System.out.println("Woof");
    }

}

Since Dog inherits from Animal, every Dog automatically gets:

without rewriting any code.

Dog dog = new Dog();

dog.Eat();
dog.Bark();

A Dog is an Animal.

This is called an is-a relationship.


Why Inheritance Became Popular

Suppose you have:

Every one of them eats.

Instead of writing:

Eat()

four different times, you write it once inside Animal.

Inheritance reduces duplicated code.


But Inheritance Has Problems

Years later, your Animal class grows.

Animal
------------
Eat()
Sleep()
Walk()
Run()
Swim()
Fly()

Suddenly problems appear.

You begin overriding methods.

class Penguin extends Bird {

    void Fly() {
        throw new Exception("Can't fly");
    }

}

Not ideal.

Eventually your inheritance tree becomes huge.

Animal
   |
Mammal
   |
Canine
   |
DomesticDog
   |
GermanShepherd

Now changing one class can accidentally affect dozens of other classes.

This is known as the Fragile Base Class Problem.

Go Chose a Different Philosophy

Instead of saying:

Dog IS an Animal

Go says:

Dog HAS behavior.

Instead of inheriting functionality, you build larger objects using smaller objects.

Think LEGO bricks.


What is Composition?

Composition means one object contains another object.

Instead of:

Dog
inherits Animal

Go prefers:

Dog
 └── Animal

The relationship changes from:

to:


Real-Life Example

A car isn't an engine.

A car has:

Those parts work together.

That is composition.


Composition in Go

type Animal struct {
    Name string
}

Now create a Dog.

type Dog struct {
    Animal
}

Notice something.

There is no:

extends

There is no:

inherits

Dog simply contains an Animal.


Creating a Dog

dog := Dog{
    Animal: Animal{
        Name: "Buddy",
    },
}

Memory looks like this:

Dog
-------------------
Animal
   Name = "Buddy"

Embedded Structs

Go has a feature called embedding.

type Dog struct {
    Animal
}

Instead of writing:

dog.Animal.Name

you can simply write:

dog.Name

Go automatically forwards the request.

It feels similar to inheritance but is actually composition.


Another Example

type Engine struct {
    Horsepower int
}

type Car struct {
    Engine
    Brand string
}

Memory:

Car
----------------
Brand
Engine
    Horsepower

You can access:

car.Horsepower

even though Horsepower belongs to Engine.


Why Composition is Flexible

Imagine building an electric car.

Instead of:

Vehicle
   |
Car
   |
ElectricCar

you simply assemble pieces.

ElectricCar

Battery
Motor
GPS
AirConditioner
Radio

Need GPS? Add GPS.

Need Radio? Add Radio.

Each component is independent.


Small Reusable Components

Suppose you have:

Build a server by combining them.

Server
----------------
Logger
Database
Configuration
NetworkClient

Rather than giant inheritance trees, Go encourages assembling software from reusable pieces.


Interfaces Make Composition Even Stronger

Go asks:

Can this object perform this behavior?

instead of:

Is this object an Animal?
type Speaker interface {
    Speak()
}

Dog:

func (d Dog) Speak() {
    fmt.Println("Woof")
}

Cat:

func (c Cat) Speak() {
    fmt.Println("Meow")
}

Robot:

func (r Robot) Speak() {
    fmt.Println("Beep")
}

None inherit from each other.

Yet they all satisfy the Speaker interface because they implement Speak().

This is called a can-do relationship.


Why Go Developers Love Composition


Real World Analogy

Think about a computer.

A computer doesn't inherit from a CPU.

It is built from components.

Computer
 ├── CPU
 ├── RAM
 ├── SSD
 ├── GPU
 ├── Motherboard
 └── Power Supply

Each part has one responsibility.

If you upgrade the GPU, you don't redesign the whole computer.

That is composition.


Inheritance vs Composition

Inheritance Composition
is-a relationship has-a relationship
Deep class hierarchies Small reusable pieces
Tight coupling Loose coupling
Parent changes affect children Independent components
Common in Java, C++, C# Core philosophy of Go

Final Thoughts

Go encourages programmers to think less about building large inheritance trees and more about assembling software from small, reusable components.

Instead of asking:

"What class should inherit from this?"

Go programmers usually ask:

"What small pieces can I combine to build this?"

That simple shift in thinking is one of the reasons Go code often feels clean, modular, and easy to maintain.