| There's usually a formal definition of something and a common definition of something, and most languages that get traction follow the common definition. For example, the formal definition of the Liskov Substitution Principal: > Let ϕ(x) be a property provable about objects x of type T. Then ϕ(y) should be true for objects y of type S where S is a subtype of T. This doesn't allow any change in behavior when subclassing. Not even the addition of logging, which makes the overriding of methods generally useless. Yet languages still provide this feature (perhaps to their detriment, but they still do). There's also a common definition of the Liskov Substitution Principal: > Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. This is, generally speaking, what people are talking about when the mention the Liskov Substitution Principal, unless they're actively writing an academic paper on the topic. Bringing up the academic definition when someone is using the common definition is 1. not relevant and 2. usually not helpful. |
Generally correct, but that's why you should only be "subclassing" abstract interfaces in the first place. Subclassing concrete object methods is a footgun, precisely because you have no way of enforcing which of these "properties" any code will actually be relying on, either at any given point in time or in the future. (Including code that's itself part of the base objects hierarchy and calling possibly-overridden methods, which means subclassing also breaks encapsulation!)
Concrete inheritance is very hard to make sense of semantically in the fully general case; if it's viable at all it is as a kind of mere specialization, and that's what the LSP is trying to get at.