Skip to content
Embedding and Composition
step 1/6

Reading — step 1 of 6

Learn

~2 min readPointers and Methods

Go has no inheritance. Instead it uses embedding — including one type inside another to compose behavior. The result feels like inheritance but is conceptually composition.

Struct embedding

go

The embedded field's fields and methods are promoted to the outer type. Reads as inheritance but it's actually a HAS-A composition with shortcut access.

Override by reimplementing

go

Cat.Greet shadows Animal.Greet. Calling cat.Greet() runs the Cat version. Call cat.Animal.Greet() to get the embedded one.

Interface embedding

Interfaces can embed other interfaces:

go

This is composition at the contract level. io.Reader, io.Writer, io.Closer are tiny interfaces in the standard library that combine to form bigger ones.

Why composition over inheritance

Classical OOP inheritance trees get tangled — diamond problem, fragile base class issues, deep hierarchies with surprising behavior. Composition is simpler:

  • Reading order matches structure — outer type's behavior is its own + embedded.
  • No deep hierarchies — you only embed what you need.
  • No override keyword — methods with the same name shadow.

Multiple embedding

go

Server has all of Logger's and Database's methods promoted. Conflict on same-name methods is a compile error — you must disambiguate by writing s.Logger.Method().

Common mistakes

  • Treating embedding as inheritance — embedded fields are still SEPARATE. dog.Name = "..." works because of promotion, but the conceptual model is composition.
  • Promoting fields you don't want — embedding exposes everything. Use a regular field if you want encapsulation.
  • Initializing without naming the embedded field: Dog{Animal{...}, "Lab"} works only if you order matches; Dog{Animal: Animal{...}, Breed: "Lab"} is clearer.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…