I see what your getting at. But this whole example is a setup. Let me go through some of your arguments to show just how easily they can be turned.
1 - "you would not expect that two out of nine of your collection also changed its height."
If two of them were Squares, I would expect height and width to mirror each other. Your saying you wouldn't expect it. Well, that is a problem if two different programmers using the same classes have two different views of the object's behavior. This can happen with any implementation of any class.
2 - "If you have cached computations that depend on the rectangles' height"
Your violating encapsulation of the object's attributes by "caching" this data elsewhere. If you need to do such things, this is what MVC was invented to handle: an attribute changes, it fires an event and dependents refresh themselves, caches invalidate, etc.
3 - "The Square class could have been written much later than her code"
Its still a Square (by my definition). The new Squares she has are still Rectangles too. Why did this programmer assume that changing a rectangle's length would never effect its width? This invalid assumption could have been made prior or after the introduction of Squares.
In short, the original argument is bad because almost everyone agrees about the behavior of a Square. Key to use of any code is agreement on how it works. For example, If I use jQuery and can't wrap my mind on how John Resig thinks I should be using his library, its my problem.
> This can happen with any implementation of any class.
From the definition of a square (a polygon with four sides of equal length) and we are trying to infer behaviour. But the definition does not require a square to remain a square after transformation; a square with a skew applied need not be a square nor a rectangle. Treating the square as a concrete class-based entity cannot capture this reality.
You are correct, this could happen with any class.
If squares are a subclass or specialization of rectangle that the consumer does not recognize then the consumer will be lied to.
They are using "rectangles" rectangles can change height apart from width and still be rectangles. But if you are a squre then you can't change height apart from width.
The consumer code has every right to expect all rectangles to work like rectangles. But squares break the rectangle contract.
As far as state goes squares are rectangles. But when it comes to behaviour or valid operations squares aren't rectangles. This is the authors point in fact and is why he says immutability makes it go away. When you bundle both state and operations into an object you make it that much more difficult to model your domain.
Another solution to the articles problem would be to have objects that only contain state. Quadrangle state objects. And other objects that contain only operations. A quadrangle resizer object. resizers know that a square which has it's height changed apart from it's width is now just a rectangle This far more accurately models the problem domain.
Squares shouldn't be responsible for knowing whether they can become just rectangles. That should be your knife operators job.
"If two of them were Squares, I would expect height and width to mirror each other. Your saying you wouldn't expect it."
No, I wouldn't expect it, because I don't know about Squares. Don't be misled because this example are uses shapes we all learn in kindergarten. The real lesson is about all the abstractions we make up all day long building applications in the real world. Think of it as Frobulator and the false subclass MagicFrobulator.
Caches happen everywhere. Going back to squares and rectangles, I stated the collection was a column. Each rectangle rests on the one before it in the collection. When I narrow the column, I set the width of every Rectangle in the collection, but now unbeknownst to me some elements have changed their height. If the column happened to be in a collection of columns sorted by height, it would now be out of sort order. The original programmer would make a reasonable assumption (well, duh) that the column sort order would not be affected by a SetWidth call.
"Its still a Square (by my definition). The new Squares she has are still Rectangles too. Why did this programmer assume that changing a rectangle's length would never effect its width? This invalid assumption could have been made prior or after the introduction of Squares."
The definition of Rectangle states that changing the width would not change the height. I don't understand your objection.
I think using something as familiar as shapes is confusing the point.
Again, go back to Frobulator and MagicFrobulator. In 2005, I invent Frobulator which has two properties foo and bar that are mutually exclusive. I release Frobulator to the world and make a million dollars.
In 2008 you have a revelation that you could make a billion dollars if you could just simplify Frobulator. You decide that you only really need foo, and you can kind of obsolete bar by making it dependent on foo. You then market this as MagicFrobulator with the pitch, "Throw out your Frobulators! MagicFrobulator is the perfect replacement."
Customers buy your MagicFrobulators and plug them in and discover to their horror that they explode in a shower of Star Trek induced sparks. As it turns out, other systems have regulated themselves by setting and getting foo and bar independently. Now, Widgets set foo and screw up Gadgets who did not expect bar to have changed. Bar just happens to control the amperage, and so the Gadgets explode.
1 - "you would not expect that two out of nine of your collection also changed its height."
If two of them were Squares, I would expect height and width to mirror each other. Your saying you wouldn't expect it. Well, that is a problem if two different programmers using the same classes have two different views of the object's behavior. This can happen with any implementation of any class.
2 - "If you have cached computations that depend on the rectangles' height"
Your violating encapsulation of the object's attributes by "caching" this data elsewhere. If you need to do such things, this is what MVC was invented to handle: an attribute changes, it fires an event and dependents refresh themselves, caches invalidate, etc.
3 - "The Square class could have been written much later than her code"
Its still a Square (by my definition). The new Squares she has are still Rectangles too. Why did this programmer assume that changing a rectangle's length would never effect its width? This invalid assumption could have been made prior or after the introduction of Squares.
In short, the original argument is bad because almost everyone agrees about the behavior of a Square. Key to use of any code is agreement on how it works. For example, If I use jQuery and can't wrap my mind on how John Resig thinks I should be using his library, its my problem.