The nightly digest looped over every channel and called send(message, attachment).
EmailChannel and PushChannel delivered fine. Then it reached SmsChannel, which
threw the instant a message carried an attachment.
Look at what the loop was doing: it held a Channel and used it exactly the way the
Channel contract allows. An SmsChannel is a Channel, so it should have been
a safe stand-in — the loop was never supposed to care which channel it got. It had
to. That broken substitution is the whole bug.
It’s the penguin problem in one sentence: a penguin is a bird, so any code expecting
a bird should be able to use it — right until it calls fly(). A subtype that can’t
do what its parent promised isn’t truly substitutable for it.
The members-only continuation runs the whole substitution test live — an interactive
island where you toggle the naive and substitutable subtypes — then the before/after
refactor code, the four contract rules a subtype may never break, the JDK’s own
List.of LSP tension, the tradeoffs, and an interview corner with a coding challenge
and quiz.
Keep reading with Premium
You've reached the members-only part of this deep-dive — the full implementation, the interactive ring simulator, and the step-by-step walkthrough. Unlock it with a membership.
Discussion
Loading the conversation…
Discussion
Loading the conversation…