3 ms·
A common example that is used is when you have a Rectangle.setSize(int width, int height) method. When you make Square a subclass of Rectange, the Liskov substi
by meuk 9y ago
A common example that is used is when you have a Rectangle.setSize(int width, int height) method. When you make Square a subclass of Rectange, the Liskov substitution principle is violated. I think this (well-known) example is what the author of the article wants to refer to.
This method is of course of type void. The problem is that by calling setSize, there is an implicit return type: the type of the object. This is assumed to be Square because this is the type of the object, but in reality the setSize method takes a Rectangle and produces a Rectangle.
If you would have a method stretch: Rectangle -> Rectangle, the Liskov substitution principle wouldn't be violated: you could substitute a Square for a Rectangle and everything would work the way it's supposed to.
- acjohnson55 9y agoThis is because by accepting data after construction with setSize, Rectangle is now invariant as a type. Immutable container types are covariant, because data only comes out. So you can apply LSP really only if you are willing to accept immutability.
- klez 9y ago> A common example that is used is when you have a Rectangle.setSize(int width, int height) method. Isn't the fact that we defined a method that changes both sizes at the same time the problem in this case? I mean, if we had two independent methods like `setBase(int)` and `setHeight(int)` this wouldn't be a problem at all (with the assumption, of course, that you accept the fact that the base changes when you change the height). Am I creating a different class of problems this way? Also, this seem rather specific to rectangles and squares. Do real-world objects (think `List` in Java) have this kind of problems at all?
- lucozade 9y agoThe same issue exists for Java Lists. Java lets you pass in subtypes of the type you specified in the List ie it treats them covariantly. This would be correct if the List was immutable but, as you can write to the List, you can blow the type relationship at runtime. In theory a List which you can both read and write should be invariant in the type parameter but this is useless in practice. So Java gives you a useful construct that isn’t completely type sound.
- klez 9y agoI wasn't talking about generics, I was talking about the `List` interface and its implementations (`ArrayList` and co). Don't they provide a common interface that doesn't leak like the rectangle/square example does? Also, I posed a question asking if I'm wrong in thinking something, was a downvote really warranted? (Not you specifically, but whoever downvoted)
- Sharlin 9y agoJava APIs are full of examples like that, with subtypes violating LSP by throwing UnsupportedOperationExceptions from methods that they cannot support.