2 types of inheritance:
as a way of combining types: to specify "this is like that except"
dynamic organization of behavior
Problems with Inheritance
Inheritance is coupling. All entities involved in inheritance are coupled together (child, parent, parent of parent). As well, the code that implements the child class is coupled with the parent's functionality (i.e., problems can appear if the parent class changes name to function or output code.)
Inheritance can lead to the development of a complex map of types. These maps of types can be complex and any change impact many layers of the map.
Alternatives to Inheritance
Interface and Protocols = specify that a class implements a set of behaviors (Javascript has no interfaces, Python has abstract classes). You get polymorphism without doing inheritance
Delegation via Composition = a class has an object of another class.
Has-A relationship vs. Is-A RelationshipMixins, Traits, Categories etc. = Instead of the child class inheriting all of the parent's classes, although it needs less, mixins can be used. In Python, mixins are still applied via inheritance, but at least you can mix different functionality. It is cool, because you give the mixin a name, and it is clear what functionality is inherited (for example the generic views in Django Rest Framework). With mixins, you can "merge/extend" existing functionality with new functionality.