Why Smalltalk has an article by David Buck on the effects of changing code. He has some damning things to say about cross dependencies, and how they are worse in C++ and Java, where the static typing is "helping" you:
I get a knee-jerk reaction, therefore, when I see language designs that require wide-sweeping propagation of changes just to make one simple design change in the system. Often, these changes have a domino effect where one change requires other changes and those in turn require others. The end result could be a tremendous amount of work.
I ran into one such case when developing C++ code. I had flagged one method (member function in C++) as const. This means that the method doesn't change any instance variables of the receiver. Over time, I had refactored the member function into several member functions that called each other several levels deep and all declared as const.
I then noticed that the lowest-level function was performing a calculation time after time. I decided that it would be more efficient to calculate it once and cache the answer in the object. By doing this, however, I changed the "const" nature of the function and I had to remove the const declaration. When I did this, the callers of this function failed to compile because const functions are not allowed to call non-const functions. I had to follow the whole tree of calls removing const declarations.
In theory, this propagation could have had a domino effect through the whole system. On large systems, this kind of propagation could make it impractical to change the code.
A similar problem exists in Java's exception handling. Java requires that the programmer specially declare methods that raise exceptions by using a "throws" clause. In addition, any callers of those methods must either handle the exception or declare that they throw it.
Now, consider what happens when you need to change low-level code to throw an exception. Typically, these exceptions are caught at a high level by the application. In order to add the throw at the low level, all methods called between the throw and the catch must be changed to state that they throw the exception. To make matters worse, it's not only that one chain from the throw to the catch that must be changed. The changes branch out into trees of callers and could span many classes throughout the system. If any of those classes happen to be general utility classes or belong to other development teams, it may be impractical to change all users and it would therefore make the addition of the exception infeasible.
and here's the money quote:
Why is Smalltalk with its dynamic typing less susceptible to these problems? Dynamic typing allows the programmer to do the right thing without trying to convince the compiler that it's the right thing. Static typing requires the programmer to provide additional information to the compiler so it can double check the code. This additional information gets in the way when the programmer needs to make changes to the system.
It's a thoughtful, well written article, well worth your time.