Go Lesson 25 – Embedding & Composition | Dataplexa

Embedding & Composition in Go

Go does not support traditional class-based inheritance like Java or C++. Instead, Go uses a powerful concept called composition, and a special form of composition known as embedding.

This design keeps Go programs simple, flexible, and easier to maintain in large production systems.


What Is Composition?

Composition means building complex types by combining simpler types. Instead of inheriting behavior, Go encourages you to reuse functionality by including structs inside other structs.

This follows the principle:

“Favor composition over inheritance.”


Basic Composition Example

Let’s start with a simple example using real-world data.

type Address struct {
    City    string
    State   string
    Country string
}

Now compose this inside another struct.

type Employee struct {
    Name    string
    ID      int
    Address Address
}

Here, Employee has an Address. This is composition.


Using Composed Structs

Let’s create and use an employee record.

func main() {
    emp := Employee{
        Name: "Arjun",
        ID:   101,
        Address: Address{
            City:    "Bangalore",
            State:   "Karnataka",
            Country: "India",
        },
    }

    fmt.Println(emp.Name)
    fmt.Println(emp.Address.City)
}

You access nested fields explicitly using the struct name.


What Is Embedding?

Embedding is a special form of composition where a struct is included without a field name.

This allows the embedded struct’s fields and methods to be accessed directly from the outer struct.


Embedding Example

Let’s embed the Address struct.

type Employee struct {
    Name string
    ID   int
    Address
}

Now Address is embedded.


Accessing Embedded Fields

Create an employee and access fields directly.

func main() {
    emp := Employee{
        Name: "Neha",
        ID:   102,
        Address: Address{
            City:    "Hyderabad",
            State:   "Telangana",
            Country: "India",
        },
    }

    fmt.Println(emp.City)
    fmt.Println(emp.State)
}

Even though City belongs to Address, it can be accessed directly through Employee.


Method Promotion with Embedding

Methods defined on embedded structs are automatically promoted to the outer struct.

func (a Address) FullAddress() string {
    return a.City + ", " + a.State + ", " + a.Country
}

Now call it from Employee.

fmt.Println(emp.FullAddress())

This works because of method promotion through embedding.


Embedding vs Inheritance

In traditional inheritance:

  • Child classes automatically inherit everything
  • Tight coupling between parent and child

In Go embedding:

  • Only selected behavior is reused
  • Loose coupling
  • Better flexibility

Multiple Embedding

A struct can embed multiple structs.

type Contact struct {
    Email string
    Phone string
}

type User struct {
    Name string
    Address
    Contact
}

Now User has fields and methods from both embedded structs.


Real-World Use Cases

Embedding and composition are widely used in:

  • HTTP request and response structures
  • Database models
  • Microservice architectures
  • Configuration management

Many Go frameworks rely heavily on embedding for extensibility.


Best Practices

  • Use composition to reuse functionality
  • Use embedding only when field promotion makes sense
  • Avoid deep embedding chains
  • Design small, reusable structs

What’s Next?

In the next lesson, you will learn about Packages and Modules in Go, which help you organize large applications and manage dependencies professionally.