Q:

Designing generic operations in object oriented languages

I found an interesting quote in SICP that I think is highly relevant in object oriented design:

We see that, in general, a type may have more than one subtype.
  Triangles and quadrilaterals, for instance, are both subtypes of
  polygons. In addition, a type may have more than one supertype. For
  example, an isosceles right triangle may be regarded either as an
  isosceles triangle or as a right triangle. This multiple-supertypes
  issue is particularly thorny, since it means that there is no unique
  way to "raise" a type in the hierarchy. Finding the "correct"
  supertype in which to apply an operation to an object may involve
  considerable searching through the entire type network on the part of
  a procedure such as apply-generic. Since there generally are multiple
  subtypes for a type, there is a similar problem in coercing a value
  "down" the type hierarchy. Dealing with large numbers of
  interrelated types while still preserving modularity in the design of
  large systems is very difficult, and is an area of much current
  research.

I think a type with many subtypes is very common in mainstream languages. A type with more than one super type is also possible with multiple inheritance or interfaces.
When I read this quote, I thought of polymorphism and casting. So I think the issue is no longer as difficult as the text implies. Did polymorphism really solve this problem?

Dealing with large numbers of interrelated types while still
  preserving modularity in the design of large systems is very
  difficult, and is an area of much current research.

Is it still true today? Or this quote is outdated? If it's still true, can you provide some examples where modelling something with related types in object oriented languages would be very difficult?
I am not familiar with language design and so I would like someone to explain if my understanding of the quote is correct.

A:

Your quote is still true today:  

Dealing with large numbers of interrelated types while still
  preserving modularity in the design of large systems is very
  difficult, and is an area of much current research.

Programming very large object oriented systems -- thus with more and more interrelated classes and dependencies -- caused mainstream language to evolve.  
C++ for example was launched in 1983 with classes and inheritance.  In 1986, B.Stroustrup has identified several missing features for object orientation and data abstraction at the large. In 1989 he added multiple inheritance to the language. While MI is (despite controversy) a very powerful language construct, its use for solving generic problems leads to dependencies that propagate through down the derivation tree.  So in 1991 templates were introduced to enable true generic programming (both for classes and functions). While this was a great way forward, it was somewhat complex to use. We had to wait 2011 to get additional type deduction features that facilitated use of templates. 
Generic programming and templates are very different from type hierarchies and inheritance.  The idea is not to raise an object to upper type as described in your SICP chapter to find some ancestor that could define generic operations. The template approach is more a term rewriting like approach where generic types of a template are matched with concrete types in an expression, allowing to deduce types and rewrite/replace/generate code at compile time. I believe that this radically different approach allowed a true breakthrough.   
Java is more recent and was created in 1995.  It has hierarchical type system without multiple inheritance, but with interfaces instead.  These allow to solve similar challenges than MI but the idea behind interfaces is the abstract type.  Over the time it appeared however that interfaces (as does MI in C++) impose typing constraints that are not always desirable, especially when solving generic problems.  So in 2004  generics were added to Java.   
So the need is demonstrated, because mainstream languages do not evolve like this if there isn't a strong demand for it.  
Some nice techniques for implementing virtual/polymorphic functions for example are explained in depth in "The design and evolution of C++",Bjarne Stroustrup, 1994 and are now widely known.  So it may seem easy, but it required lots of work to arrive here.  For multiple inheritance, there are several patents that describe ways to implement it in a compiler  (I don't know though if they are still in force). So what appears obvious now, is not necesarily as obvious if it had to be invented from scratch, as the time lapse in language history suggests.  

