Go

Interfaces

Structs & Methods showed Go has no inheritance. So how does Go get the "treat different types uniformly" benefit that C++'s polymorphism provides? Interfaces — a completely different mechanism, with a genuinely surprising property: a type never declares which interfaces it implements. It just does, or it doesn't, based purely on which methods it has.

Quick reference
What it is
A set of method signatures — any type with all of those methods automatically satisfies the interface, with no explicit declaration required.
Mental model
C++ polymorphism is a family tree — a type explicitly says which base class it belongs to. A Go interface is a duck test: if it has the right methods, it qualifies, no family relationship needed at all.
Key numbers
The empty interface interface{} (or its alias any) is satisfied by literally every type — Go's escape hatch for "accepts anything."
Reach for it when
A function needs to work across multiple types that share behavior but not a common base type — exactly where C++ would reach for an abstract base class and virtual functions.

Defining and implementing an interface

type Shape interface {
    Area() float64   // any type with an Area() float64 method satisfies Shape
}

type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }

type Square struct {
    Side float64
}
func (s Square) Area() float64 { return s.Side * s.Side }

func printArea(s Shape) {
    fmt.Println(s.Area())
}

printArea(Circle{Radius: 5})   // 78.5397
printArea(Square{Side: 4})      // 16 — same function, different concrete type

Implicit implementation — the big difference

Notice what's missing from Circle and Square above: neither one ever wrote implements Shape anywhere. Compare this directly to C++, where a class has to explicitly derive from an abstract base class:

// C++: EXPLICIT — Circle must say it derives from Shape
class Circle : public Shape {
    float area() override { ... }
};

// Go: IMPLICIT — Circle satisfies Shape just by having the right method, no declaration
type Circle struct { Radius float64 }
func (c Circle) Area() float64 { ... }   // that's it — Circle IS a Shape now, automatically

This means a type can satisfy an interface it was never written with in mind — even one defined in a completely different package, written by someone else, years later. It's a genuinely different way of thinking about "what type is this" than C++'s explicit class hierarchies.

The empty interface

func describe(v interface{}) {   // interface{} (or "any") accepts a value of ANY type
    fmt.Println(v)
}

describe(42)
describe("hello")
describe(Circle{Radius: 5})

An interface with zero required methods is satisfied by every type, since there's nothing to fail to implement — Go's version of a fully generic parameter, used before Go added true generics, and still common in APIs that genuinely need to accept anything.

Type assertions

Given an interface value, you can ask what concrete type is actually behind it — Go's version of C++'s dynamic_cast, but returning a value and a boolean instead of a null pointer on failure:

var s Shape = Circle{Radius: 5}

circle, ok := s.(Circle)   // "is s actually a Circle?"
if ok {
    fmt.Println(circle.Radius)   // 5
}

square, ok := s.(Square)   // s is NOT a Square
if !ok {
    fmt.Println("not a square")   // not a square
}

This (value, ok) shape is the same pattern from Functions & Multiple Return Values — Go reuses this one idea everywhere instead of introducing a separate mechanism per feature.

Real-world applications

Gotchas

Field notes