thecodex.expert · The Codex Family of Knowledge
Go

Embedding

Embedding looks like inheritance at the call site, but underneath it’s composition — there’s no shared base class, just a field that happens to have no name.

Go 1.26 Composition, not inheritance Last verified:
Canonical Definition

Embedding declares a field using only a type name, with no field name of its own. The embedded type’s fields and methods are then “promoted” to the outer struct, so they can be accessed as if they belonged to it directly. This is Go’s deliberate substitute for classical inheritance: it’s plain composition under the hood (the outer struct literally contains the inner one as a field), not a subtype relationship — an embedded type’s methods don’t know about the struct embedding them, and there’s no polymorphism via embedding alone.

Field and method promotion

An embedded type's fields and methods become accessible directly on the outer type, without an extra level of dot notation:

Goembedding.go
type Base struct {
    Name string
}

func (b Base) Describe() string {
    return "I am " + b.Name
}

type Employee struct {
    Base       // embedded: no field name, just the type
    Salary int
}

e := Employee{Base: Base{Name: "Alice"}, Salary: 50000}
fmt.Println(e.Name)         // promoted field, no e.Base.Name needed
fmt.Println(e.Describe())   // promoted method

It's composition, not inheritance

The distinction matters in practice: if Describe were changed to call another method that Employee overrides, the embedded Base.Describe would still call Base's version, not Employee's — there's no dynamic dispatch the way a real subclass would have. You can still access the embedded value explicitly via its type name (e.Base), and if the outer type declares its own field or method with the same name, that shadows the promoted one.

Interface embedding

Interfaces can embed other interfaces too, composing a larger interface from smaller ones — this is how the standard library builds up io.ReadWriter from io.Reader and io.Writer without repeating method signatures.

Gointerface_embedding.go
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type ReadWriter interface {   // composed from both
    Reader
    Writer
}

Sources

1
The Go Authors. "Effective Go", "Embedding" section, go.dev/doc/effective_go#embedding.