From a purist view one could argue that inheritance doesn't belong in OO in the first place. Alan Kay's first descriptions of Smalltalk & OOP did not include inheritance concepts.
class A {
public int field1;
public void method1() {
System.out.println("A");
}
public void method2() {
System.out.println("A");
}
}
class B extends A {
public int field2;
public void method1() {
System.out.println("B");
}
}
is basically equivalent to interface C {
public void method1() {}
public void method2() {}
}
class A implements C {
public int field1;
public void method1() {
System.out.println("A");
}
public void method2() {
System.out.println("A");
}
}
class B implements C {
public A a;
public int field2;
public void method1() {
System.out.println("B");
}
public void method2() {
a.method();
}
}
As you can see both are basically the same except one little detail. The benefit is that you don't have to write the redundant "method2" method in class B. So the only time inheritance is ever useful is when you don't want to override all methods. Now someone tells you to model everything in terms of class hierarchies even when they don't need it right now and you've negated the tiny little benefit it ever had which means not having it in the programming language actually has positive consequences.The upshot is that to teach OOP in Java, say, you need to talk about significant parts of the inheritance machinery just to get dynamic dispatch, perhaps later cautioning against implementation inheritance and even interface inheritance.
In Smalltalk, you can talk dynamic dispatch without messing around with inheritance at all.
For a statically typed language where dynamic dispatch is free from inheritance graphs (sometimes described by saying that subtyping is not inheritance) see Ocaml's structural subtyping via row polymorphic records (bit of a mouthful --- but I need to differentiate from Ocaml's module system which is structurally subtyped and supports inheritance!)