5 ms·
You may quibble, but what I presented is more or less the textbook example that is often used to illustrate the LSP. I would argue that it is reasonable for an
by adamlett 10y ago
You may quibble, but what I presented is more or less the textbook example that is often used to illustrate the LSP.
I would argue that it is reasonable for any client of the Rectangle interface to make the assumption the setting the height does not affect the width and vice versa. The unreasonable part is providing such an interface to begin with. As a client of an interface, I shouldn't have to think carefully about whether or not certain assumptions I make, may be invalid in certain specific instances. If I make use of the Rectangle interface to model a resizable window in the GUI, I shouldn't have to worry how my GUI might behave if a Rectangle happens to be a Square.
If your reaction is: “but you're doing it wrong!”, we are in agreement. But to reiterate, the thing I'm doing wrong is not to make (sometimes) invalid assumptions about the behavior of Rectangle, but to make it possible to make invalid assumptions by violating the LSP.
- masklinn 10y ago> As a client of an interface, I shouldn't have to think carefully about whether or not certain assumptions I make, may be invalid in certain specific instances. As a client of an interface you shouldn't make assumptions which are not guaranteed by the interface in the first place. > If I make use of the Rectangle interface to model a resizable window in the GUI, I shouldn't have to worry how my GUI might behave if a Rectangle happens to be a Square. The fixed aspect-ratio issue (square or not) actually applies very well to this scenario, video players will often have a fixed aspect-ratio (matching that of the video they're playing + some decoration), and while you can control the width or height: 1. there's no guarantee that they're independent 2. there's no guarantee that your setting a specific width or height will be acknowledged or unbounded That is not only setting the width may change the height (and vice-versa), there's no guarantee `r.SetWidth(x); x == r.GetWidth()` holds. And the interface certainly makes no such promise.
- adamlett 10y agoAs a client of an interface you shouldn't make assumptions which are not guaranteed by the interface in the first place. Sure. But as an author of an interface you should strive to make your interface easier to use correctly. It's easy to blame the programmer who makes the wrong assumptions about your code, but if you can make your interface in way that reduces the possibility of that happening, why wouldn't you? Large software platform vendors are generally more succesful if they instead of blaming application developpers for misusing the APIs, change the APIs so that they are easier to use correctly. The fixed aspect-ratio issue (square or not) actually applies very well to this scenario, video players will often have a fixed aspect-ratio (matching that of the video they're playing + some decoration), and while you can control the width or height [...] A video player getting getting its window locked to the aspect of the video it is playing may be the desired behaviour. Or not. In any case, it should be the video player that makes this decision, not whomever provides the video. Imagine you have an video library API that returns a Rectangle with the dimensions of the video, which previously returned a Rectangle proper (ie. one that allows changing width and height independently). In a recent update however, it changes its internal implementation, and while the signature of the API is unchanged (it still returns a Rectangle), it now returns a Square. This has the effect of changing the behaviour of your application though nothing in it has changed!
- masklinn 10y ago> Sure. But as an author of an interface you should strive to make your interface easier to use correctly. Yes? > It's easy to blame the programmer who makes the wrong assumptions about your code, but if you can make your interface in way that reduces the possibility of that happening, why wouldn't you? I really don't see what point you're trying to make. > Large software platform vendors are generally more succesful if they instead of blaming application developpers for misusing the APIs, change the APIs so that they are easier to use correctly. Well yes, that pretty much my point. The original interface as you defined it is either unreliable if you interpret it literally (and allow fixed-aspect-ratio or even fixed-size rectangles) or completely pointless if you interpret it "smartly" (since it pretty much mandates one specific implementation). > A video player getting getting its window locked to the aspect of the video it is playing may be the desired behaviour. Or not. In any case, it should be the video player that makes this decision, not whomever provides the video. The video player can be an application or a component, it makes no difference. If the video player is an application it changes the behaviour of your OS's maximize or fullscreen feature, or the behaviour of your window-resizing script, or whatever.
- adamlett 10y agoWell yes, that pretty much my point. The original interface as you defined it is either unreliable if you interpret it literally (and allow fixed-aspect-ratio or even fixed-size rectangles) or completely pointless if you interpret it "smartly" (since it pretty much mandates one specific implementation). Are you somehow under the impression that I am advocating the example I gave as something to emulate? Your argument seems to be that the example of bad design I gave, is bad design. I'm aware of that, thank you. I'm trying to illustrate why it's bad design. It turns out that this particular bad design is common enough that it has been studied, and it has a name (well not quite, but the principle you have to follow to avoid, it has a name). You may think that my example is contrived, but exchange Rectangle for Window and FixedAspectWindow for Square, and you have something which looks reasonable to most OOP novices. The reason the problem arises is that in classical OOP we are taught that subclasses should be specializations of the parent class. It seems reasonable therefore to make Square a subclass of Rectangle (or FixedAspectWindow a subclass of Window).
- catnaroek 10y agoThe Liskov substitution principle always holds in a type-safe language with subtyping. What is failing isn't the LSP, but rather your expectations from types. Just because a type is called “Rectangle”, it doesn't mean its instances actually behave like rectangles. See: http://blog.tmorris.net/posts/identifier-names/index.html http://blog.tmorris.net/posts/identifier-names/index.html
- adamlett 10y agoThere is no such thing as a "type safe language". Type safe is a subjective value judgment.
- catnaroek 10y agoIt's not subjective: The operations allowed on a Go value or object are precisely those that are sanctioned by its type. The problem for Go programmers is that Go types don't mean what they think they mean.
- adamlett 10y agoThat's true for all programming languages. That's literally how all bugs get created. Are you claiming that there exists some language where bugs cannot happen because it is "type safe"?
- catnaroek 10y ago> That's true for all programming languages. I'm pretty sure that when I define abstract types in ML, I can often arrange things so that they mean what I want them to mean. For example, I can define set and heap types that are impossible to use in any other way than as sets or heaps. Of course, I still have to manually prove that my implementation is correct, but the language guarantees that, if my implementation is correct, it's impossible to misuse. The problem with Go is that the type system is too dumb to actually enforce such things, so the names of your types are nothing but declarations of good intentions. So you might as well use a dynamically typed language, since you have nothing to lose but the verbosity. > Are you claiming that there exists some language where bugs cannot happen because it is "type safe"? No, I didn't say that.