I mean Erlang is an actual OOP language according to the original creator of OOP's concept of message passing between objects. But each object internally is quite functional.
It's just the Java crowd's deep inheritance enterprise code that makes every developer who survived that want to vomit.
IMO, that seems like too formulaic an approach without enough thinking in that step.
Also, you mention design patterns, but the classic design pattern book nicknamed GoF (Gang of Four, i.e. by Gamma, Vlissides et al), has this guideline prominently on an early page (before the main body of text):
"Prefer composition over inheritance"
, or similar words (from memory).
And that is the only sentence on that page, right in the middle, which could only have been done for great emphasis.
But you say:
3. If interfaces are not enough, use composition
And although you do say to avoid inheritance, aren't interfaces somewhat similar to inheritance, so shouldn't the same GoF guideline apply?
Asking for myself.
"Program to an interface, not an implementation"
and this actually comes before the other one about composition.
Inheritance (i.e. implementation inheritance) creates tight coupling between classes, whereas interfaces exist to prevent that happening, ... they are quite different constructs.
I think the main reason what people get wrong about OOP is that they tend to think everything needs to be models with inheritence, which is completely wrong. Inheritence is BAD!
The rule should be:
1. Avoid inheritance
2. Use interfaces instead
3. If interfaces are not enough, use composition
4. If composition is not enough go through all other similar design patterns that are not based on inheritance.
5. If you really need inheritance, be very careful about which function you make non-final and non-private.