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 witherrors.Is/As.panic/recoveris 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
- Q551How do variadic functions work? What is the aliasing trap when passing s... to a function that modifies or appends to its argument?
- Q552Explain closures in Go: what they capture, when captured variables escape to the heap, and how to build a generator or middleware with them.
- Q554Can you compare functions in Go? Why is a func only comparable to nil, and how does that affect using funcs as map keys?
- Q555Does Go do tail-call optimization? What happens with deep recursion, and what does "goroutine stack exceeds 1000000000-byte limit" mean?
- Q556How do you structure a large Go project (cmd/, internal/, pkg/ debate)? How should packages be named and split to avoid stutter and cycles?
- Q557How do you do dependency injection in Go? Compare manual constructor wiring with google/wire and uber/fx.