Go

Why does Go have no inheritance, function overloading, default arguments, ternary operator or exceptions? How do idiomatic Go programs work around each?

Question 553MediumGo 1.22 to 1.25

Go's designers value code that is easy to read and maintain at scale, where every call site is unambiguous, over expressive power. Each missing feature has an idiomatic replacement:

  • Inheritance: deep hierarchies are fragile (the fragile base class problem). Use composition via embedding for reuse and implicit interfaces for polymorphism. Embedding promotes methods but is not subtyping: there is no virtual dispatch back into the outer type.
  • Overloading: it makes it harder to tell which function is called. Use distinct names (strconv.ParseInt / ParseFloat), variadics, or generics.
  • Default args: use functional options, a config struct with meaningful zero values, or cmp.Or(v, def) (Go 1.22), which returns the first non-zero argument.
  • Ternary: nested ternaries hurt readability. Use if/else, or a small generic helper if you really must.
  • Exceptions: they hide control flow. Errors are values: return error, wrap with %w, inspect with errors.Is/As. panic/recover is reserved for programmer bugs and for cases where the program cannot continue.
type Base struct{}
func (Base) Hello() string { return "base" }
func (b Base) Greet() string { return b.Hello() }

type Derived struct{ Base }
func (Derived) Hello() string { return "derived" }

fmt.Println(Derived{}.Greet()) // "base": no virtual dispatch through embedding

Interviewer angle: show that you understand the trade-off (explicitness and tooling-friendliness) rather than just reciting the list.

More on Go Idioms, Design Patterns & Language Design

All 16 Go Idioms, Design Patterns & Language Design questions