That said, I think this is also a good way to approach framing things. Agreed that the idea of "prefer composition" is often a thought termination trick. Instead, try them both! The entire point of preferring one technique over the other is that it is felt to give more workable solutions. If you don't even know what the worked solution would look like with the other technique, you should consider trying it. Not with a precommitment that you will make it work; but to see what it illuminates on the ideas.
I used to do a talk about Liskov that included the joke “CLU didn’t support object inheritance. The reason for this is that Barbara Liskov was smarter than Bjarne Stroustrup.”
Oh the damage that language has done to a generation, but at least it is largely passed us now.
Considering sets, if something is, in set terms a specific subset with a defining membership or characteristic of a definable superset, representing that at compile time effects a hard constraint which honours the set Venn diagram.
If that set/subset constraint doesn't exist then you have to ask yourself if applying a compile time constraint is appropriate.
Inheritance is just a more deeply integrated form of composition which puts the inherited parts on equal footing with the new parts.
That reduces certain indirections and frictions, which is sometimes useful when making things out of other things.
it's mentally satisfying to create a beautiful class hierarchy that perfectly compresses the logic with no repetition, but i think long term readability, maintainability and extensibility are much better when inheritance is avoided in favor of flat interfaces. (also easier to turn into rpcs as all the overcomplicated object rpc things of the 90s were put to bed).
gishh•1h ago
So, we just need devs to stop trying to be overly clever? I can get behind that, “clever” devs are just awful to work with.