And on the topic of Go, note how most common OO languages in use still have more convenient support for inheritance than composition, where "inheritance" is one token in the right place but "composition" takes a lot more boilerplate because there's no support built in, or you have to add a third-party library to make the boilerplate go away. Again, changing over time, but languages change slowly.
type TwoComposedThings struct {
ThingOne
ThingTwo
}
where ThingOne and ThingTwo are types. If ThingOne and ThingTwo do not have any conflicting method names, you're done. (If they do, you can actually still compile but when you try to use a conflicting name you'll have to manually disambiguate, and some subtleties could arise.)Messy inheritance still plagues product Java, C#, and, with the increasing proliferation of MVC frameworks, JS these days.
Hierarchies usually start out small. But, when new features are added and scope creeps, they get deeper and more abstract and messier.
Substitutability (i.e. the L in SOLID principles) does require more boiler-plate when using composition though. Interfaces and mixins (if available in your language) go some way to helping.
The "inheritance based" things mostly got deprecated/replaced when Java 1.5 introduced generics and most libraries needed to be heavily changed anyways.
I guess it's different when you're maintaining a library - you have more freedom to version up and rewrite things.
This. There aren't enough dead single reponsability horses :P. This should be drilled in new and experienced programmers over, and over, and over again. And then some more. Because while it sounds so simple it's actually all to easy too violate and because it applies to each and every layer of a project. I'd even say most design patterns are actually proper implementations of SRP in one way or another. Most of the time I have a feeling something if off with my code, it boils down to some pieces just doing too much, hereby dragging others down with it.
Anecdote applied to this particular topic: the intern, proud of having used composition as much as possible, creating mostly classes composed of 10+ other classes and functions that might as well be called NowDoItAll().
We have real issues with some complex class hierarchies that another team likes - they keep adding yet another abstract subclass of an abstract subclass to handle more cases, so you can end up following logic up and down multiple levels of classes when reading code, and missing one overridden statement can dramatically change the outcome.
And everyone likes to read stuff that reinforces their own belief :)
I graduated college about 10 years ago, and I was never taught anything near composition over inheritance. I was told about inheritance, but had to learn from other coworkers and experience that composition is much favored over inheritance. Now I mentor a number of junior developers and they need to be told composition over inheritance often. This isn't a problem that has fixed itself, and it's most certainly not beating a dead horse when it needs to be repeated for so many young programmers.
This isn't just a problem with formal CS courses - code schools like Hacker School and Flatiron School have this issue as well. It seems more natural and intuitive to inherit than compose. So this horse needs to continue being being as it's very much alive.
You weren't taught that, because it isn't true. Inheritance is appropriate sometimes, composition at other times.
In particular, when a two objects are modeled by an ISA relationship, you should use inheritance. When they're modeled by HASA, you should use composition.
A Dog is not an Animal that includes Barkable and PeeOnHydrantable, and a SpaceShuttle is not a descendant of Airplane.
Just saying "use the tool appropriate to the job" dismisses the entire problem where in the real world, it isn't clear what that is.
Even in marginal cases, you can reasonably decide that a data model should use inheritance. There's no presumptive bias against it.
I think there is probably a lot of room for debate on this.
(Edited to make it less pithy and therefore probably much less irksome)
Especially when you finally figure out inheritance and OO you fall in to that "when all you have is a hammer".
Composition is not an obvious way to approach this problem when you've been taught to solve problems with inheritance - and it fits "so nicely".