Skip to main content

Keep the Promise

The Liskov Substitution Principle says: anywhere the code expects an interface, every implementation of that interface must work correctly. An implementation that technically fits but behaves badly — panics, does nothing, lies — breaks every function that trusted the interface.

An interface is a promise. Fly() promises flying. A type that implements Fly() by crashing has signed a contract it cannot keep.


A Substitute That Breaks the Deal

The Bird interface promises Fly(). Sparrows deliver. Penguins are birds too — so it feels natural to implement the interface... with a panic, because penguins cannot fly.

Now airShow, which works for every honest bird, crashes on a penguin. The bug is not in airShow — it is in the substitute that broke the promise.

The penguin that crashes the show

airShow trusts the interface and calls Fly() on every bird. The sparrow performs; the penguin panics and takes the whole program down (the recover only softens the landing to show the message).

Prompt
Write a Go program showing a Liskov Substitution violation: a Bird interface with a Fly method, a Sparrow that flies, and a Penguin whose Fly panics because penguins cannot fly. An airShow function calls Fly on every bird; use recover in main to show the crash message when the penguin performs.
Output: Go program and captured output

Separate the Promises

The fix: promise only what is true. Split the fat promise into Flyer and Swimmer. The sparrow implements Flyer, the penguin implements Swimmer — and no type signs a contract it cannot keep.

The best part is who catches the mistake now: passing a penguin to airShow is no longer a crash at runtime — it is a compile error. The program will not even build.

Every type keeps its promise

airShow accepts Flyer, poolShow accepts Swimmer. Each animal appears only where its promise holds — substitution is safe by construction.

Prompt
Fix the Liskov violation in Go by splitting the promises: a Flyer interface with Fly and a Swimmer interface with Swim. Sparrow implements Flyer, Penguin implements Swimmer. Write airShow for flyers and poolShow for swimmers and run both, so every type only appears where its promise holds.
Output: Go program and captured output
Every type keeps its promise

Any Flyer can join

The payoff of honest interfaces: a new Eagle joins the air show with no risk — anything that implements Flyer truly flies, so airShow never needs to doubt its input.

Prompt
Extend the Go Flyer interface example with a new Eagle type and run an air show with several flyers, showing that any honest Flyer implementation can substitute safely.
Output: Go program and captured output