From Wikipedia,
Liskov's notion of a behavioral subtype defines a notion of
substitutability for objects; that is, if S is a subtype of T, then
objects of type T in a program may be replaced with objects of type S
without altering any of the desirable properties of that program (e.g.
correctness).
Suppose the following class hierarchy:
The base abstract class - AnimalWithFur. It has a read-only property furColor that is overridden in successors.
Base class's successor - Cat, which overrides furColor and returns gray.
Cat's successor - Tiger, which overrides furColor and returns striped.
Then we declare a method with an argument of type Cat (not AnimalWithFur).
Is sending a Tiger instance to that method a violation of the L in SOLID?
Strictly speaking, yes. The wiki article summation of Liskov says:
"...in a program...without altering any of the desirable properties of that program"
If you go back to the original paper by Barbara Liskov, it's literally stricter in its wording, 3.3.
Type Hierarchy:
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2
(Empahsis mine)
So if you replace an instance of Cat with another instance that does something different, i.e. returning stripped not grey, then that is a Liskov violation in the original sense, because a program could be easily defined that relies on the color being grey, here:
program(Cat c){
println(c.furColor);
}
The behaviour of that program will change if you pass it a Tiger in place of a Cat.
However, in the normal way LSP is applied, it is not a violation if you did not add extra preconditions or postconditions. This is a more practical, less academic definition as people accept that when replacing an instance of one concrete type with another you do intend to change the behaviour of the program while maintaining desirable properties of that program. So presuming the client code can handle stripped like any other colour, and grey was not required for a "desirable" property of the program then it does not violate.
Short answer: not necessarily. I'd have said not with the information you've given. The key, for me, is that you don't say what the imagined new method is supposed to do.
You might consider the behaviour that you're requiring in your new method to be more important than the concern of a class hierarchy.
One way to do this is to define an interface for the behaviour your new method needs from the passed in instance / argument.
Then whichever class you might want to pass into that method can implement that interface and you break apart the concern of an inheritance hierarchy and move to being concerned with consistency of behaviour.
Your question nicely describe why to use class composition instead of class inheritance. Firstly, your code is illogical - Tiger is not a Cat in your sense, Tiger is one of Cats family. From code point of view, it is bad design to override and totally replace the behavior of parent class, this is actually liskov substitution violation - your Cat class means defined cat with some concrete color, and application expects to work with it respectively, but you are overriding it with inconsistent type and change the behavior.
If you would describe types hierarchy correctly, you would have abstract type Cat without furColor implemented, and types Tiger and HomeCat, but HomeCat could have different color, isn't?
If you want to have trivial example of LS violation, e.g.:
You are extending List interface with custom implementation, returning size always 10, but with different count of objects inside. Each normal application expects to work with list using for statement, but will have unpredictable behavior because you've broken LS principle, and List object does not behave as it is expected.
Related
Diamond problem is handled in some OOPS languages (eg. curl) by having the repeatedly inherited class as "shared"? I want to know how this works. Also, I want to know the role played by primary and secondary constructors in solving the diamond problem in these OOPS languages when shared strategy is used.
Suppose there are 4 classes say A,B,C and D. Let the inheritance structure is B and C inherit A and D inherits both B and C. Each class has a variable say A has a, B has b, C has c and D has d. How does the object creation happens for each class?
Citing Wikipedia at https://en.wikipedia.org/wiki/Multiple_inheritance at the Curl
bullet:
Curl allows only classes that are explicitly marked as shared to be
inherited repeatedly. Shared classes must define a secondary
constructor for each regular constructor in the class. The regular
constructor is called the first time the state for the shared class is
initialized through a subclass constructor, and the secondary
constructor will be invoked for all other subclasses.
From here, without knowing Curl and only with the quote above and this, where it is stated that
The object semantics of Curl are similar to those of Java and C++.
Given
A
/ \
B(A) C(A)
\ /
D(B,C)
I imagine (I don't know for sure) that the coder is responsible to disambiguate the problem by specifying the qualified name of the constructor to run, when invoking a parent constructor from the D(B,C) subclass.
It looks like A has to be declared shared, and when D is created, B runs a constructor that calls A (primary) constructor, C runs a constructor that calls A (secondary) constructor. The distinction between primary/secondary constructor call is automatic and transparent to the coder.
As two A constructors are invoked, two A objects are created in memory, that is the A class is shared with two different subclasses, but there is not a single "shared" A object, but two independent ones (see also virtual/nonvirtual inheritance that is somehow related (C++).)
For what I've read for several different languages, it is almost always the coder that disambiguates the diamond problem with qualification. Languages just define different or similar schemes of giving an error, or having a criteria to choose one of the multiple ambiguous definitions, like specific search order in the inheritance chain. Some other languages don't even allow multiple inheritance, but in some of these you are allowed to extend functionality by some ohter means (like interfaces).
I am studying liskov substitution principle. It says sub classes should be proper replacement for the base classes.
I read an example which I found at various places in the internet. A class Rectangle.java with height, width and their setter and getter methods. A class Square.java which requires only one attribute i.e length. If we have Square.java extending Rectangle.java then this is an violation of this principle. This is because the users of Rectangle.java expect width not to get affected if only height is modified and vice-versa.
My doubts:
The situations we see where methods are just overridden with empty open and close braces in order to prevent the execution of default code written in the base class. Are such cases violation of this principle ?
This principle also says inheritance should not be used just for reusing the code. Does in case as below it is a bad practice and is this a violation of this principle ?
If a class Window.java is available from some Graphic library. Suppose it has all the code necessary to draw a window. Also suppose it has a toolbar when it is used and drawn. If the requirement is to create a window without toolbar.
Simply Creating a WindowWithoutToolBar.java extending Window.java and
overriding the drawToolBarMethod() and leaving it with empty body
solves the purpose.[May be just create toolbar and not draw it so as to avoid any exceptions occurring from other methods trying to access toolbar object] Is this a bad practice ?
Creating a whole new Window class without toolbar would have required to rewrite all the code already written in Window.java.
In case of Numbers, If we have a class Integer.java with code in it for various arithmetic operations that can be done with an integer like squaring etc. If we have later need of NaturalNumber.java we can easily extend it from existing Integer.java and add checks to take only positive integers as input.
Now if we need AbsoluteNumber.java then in case we extend it from
Integer.java does this violates this principle (in case Integer.java
has some method as getValueAfterMultiplyByNegativeOne()) ?
Please provide your valuable feedback.
Regards,
Krishna Kumar
Interesting question.
As far as I understand, it would not be a violation iif leaving the method empty does not change the expected behaviour of that type. Basically, it strengthens the sub-typing requirements by not only respond to "a Square is a Rectangle", but also that its whole interface yields the same behaviour. For instance, what you mentioned about setting a rectangle's width should not affect its height.
Definitely inheritance should not be used only for code re-use. If it actually applies to all possible sub-types, then go ahead, you'll probably be fine. If it only applies to a sub-set of them, you'll find yourself constantly overriding methods and, at the end of the day, writing more code.
You can instead encapsulate that common code into meaningful components that can then be used within your classes by means of composition.
In the case of Numbers, I think you're parting from the wrong premise. I would not extend Integer class to implement Naturals. Think when subtracting two naturals, where the second is higher than the first one: ie. 3 - 5. In here, you'd need to make a choice, which would be either to throw an Exception or to return something that is no longer a Natural. A different approach would be to extend an abstract Number class, where you could define a set of methods as follows:
abstract class Number {
public abstract Number sum(Number other);
public abstract Number subtract(Number other);
public abstract Number multiply(Number other);
public abstract Number divide(Number other);
}
This implementation would not be perfect, since it would require some assumptions to be made, like what implicit conversions (casts) to do in case you're operating upon different types. But in this case, it'd allow you to apply the Liskov Substitution principle a bit more freely.
I would say it is not a violation. I think it would be a violation if you throw an exception like
throw new Exception('Not implemented');
When this exception is not expected / documented in the base class / interface.
That means if you substitute an existing class with yours, it would throw an exception, where base class did not tell, and code could break, because someone might not implement a try catch block around.
Inheritance "should" not be used in most cases to reuse code. Composition is the way to go. I would say it is a bad practice. Just my thoughts.
I am reading Head First Object Oriented Design to get a better understanding of OOP concepts.
Polymorphism is explained as:
Airplane plane = new Airplane();
Airplane plane = new Jet();
Airplane plane = new Rocket();
You can write code that works on the superclass, like an airplane, but will work with any of the subclasses. :- * Hmmm.. ..I got this one.*.
It further explains:
-> So how does polymorphism makes code flexible?
Well, if you need new functionality, you could write a new subclass of
AirPlane. But since your code uses the superclass, your new class will work
without any changes to the rest of your code.
Now I am not getting it. I need to create a sublass of an airplane. For example: I create a class, Randomflyer. To use it I will have to create its object. So I will use:
Airplane plane = new Randomflyer();
I am not getting it. Even I would have created an object of a subclasses directly. Still I don't see a need to change my code anywhere when I will add a new subclass. How does using a superclass save me from making extra changes to the rest of my code?
Say you have the following (simplified):
Airplane plane = new MyAirplane();
Then you do all sorts of things with it:
List<Airplane> formation = ...
// superclass is important especially if working with collections
formation.add(plane);
// ...
plane.flyStraight();
plane.crashTest();
// ... insert some other thousand lines of code that use plane
Thing is. When you suddenly decide to change your plane to
Airplane plane = new PterdodactylSuperJet();
all your other code I wrote above will just work (differently, of course) because the other code relies on the interface (read:public methods) provided by the general Airplane class, and not from the actual implementation you provide at the beginning. In this way, you can pass on different implementations without altering your other code.
If you hadn't used an Airplane superclass and just written MyAirplane and PterdodactylSuperJet in the sense that you replace
MyAriplane plane = new MyAirplane();
with
PterdodactylSuperJet plane = new PterdodactylSuperJet();
then you have a point: the rest of your code may still work. But that just happens to work, because you wrote the same interface (public methods) in both classes, on purpose. Should you (or some other dev) change the interface in one class, moving back and forth between airplane classes will render your code unusable.
Edit
By on purpose I mean that you specifically implement methods with the same signatures in both MyAirplane and PterodactylSuperJet in order for your code to run correctly with both. If you or someone else change the interface of one class, your flexibility is broken.
Example. Say you don't have the Airplane superclass and another unsuspecting dev modifies the method
public void flyStraight()
in MyAirplane to
public void flyStraight (int speed)
and assume your plane variable is of type MyAirplane. Then the big code would need some modifications; assume that's needed anyway. Thing is, if you move back to a PterodactylSuperJet (e.g. to test it, compare it, a plethora of reasons), your code won't run. Whygodwhy. Because you need to provide PterodactylSuperJet with the method flyStraight(int speed) you didn't write. You can do that, you can repair, that's alright.
That's an easy scenario. But what if
This problem bites you in the ass a year after the innocent modification? You might even forget why you did that in the first place.
Not one, but a ton of modificatios had occurred that you can't keep track of? Even if you can keep track, you need to get the new class up to speed. Almost never easy and definitely never pleasant.
Instead of two plane classes you have a hundred?
Any linear (or not) combination of the above?
If you had written an Airplane superclass and made each subclass override its relevant methods, then by changing flyStraight() to flyStraight(int) in Airplane you would be compelled to adapt all subclasses accordingly, thus keeping consistency. Flexibility will therefore not be altered.
End edit
That's why a superclass stays as some kind of "daddy" in the sense that if someone modifies its interface, all subclasses will follow, hence your code will be more flexible.
A very simple use-case to demonstrate the benefit of polymorphism is batch processing of a list of objects without really bothering about its type (i.e. delegating this responsibility to each concrete type). This helps performing abstract operations consistently on a collection of objects.
Let's say you want to implement a simulated flight program, where you would want to fly each and every type of plane that's present in your list. You simply call
for (AirPlane p : airPlanes) {
p.fly();
}
Each plane knows how to fly itself and you don't need to bother about the type of the planes while making this call. This uniformity in the behaviour of the objects is what polymorphism gives you.
Other people have more fully addressed your questions about polymorphism in general, but I want to respond to one specific piece:
I am not getting it, even I would have create an object of subclasses
directly.
This is actually a big deal, and people go to a lot of effort to avoid doing this. If you crack open something like the Gang of Four, there are a bunch of patterns dedicated to avoiding just this issue.
The main approach is called the Factory pattern. That looks something like this:
AirplaneFactory factory = new AirplaneFactory();
Airplane planeOne = factory.buildAirplane();
Airplane planeTwo = factory.buildJet();
Airplane planeThree = factory.buildRocket();
This gives you more flexibility by abstracting away the instantiation of the object. You might imagine a situation like this: your company starts off primarily building Jets, so your factory has a buildDefault() method that looks like:
public Airplane buildDefault() {
return new Jet();
}
One day, your boss comes up to you and tells you that the business has changed. What people really want these days are Rockets -- Jets are a thing of the past.
Without the AirplaneFactory, you'd have to go through your code and replace possibly dozens of calls to new Jet() with new Rocket(). With the Factory pattern, you can just make a change like:
public Airplane buildDefault() {
return new Rocket();
}
and so the scope of the change is dramatically reduced. And since you've been coding to the interface Airplane rather than the concrete type Jet or Rocket, this is the only change you need to make.
Suppose you have methods in your Controller class of Planes like
parkPlane(Airplane plane)
and
servicePlane(Airplane plane)
implemented in your program. It will not BREAK your code.
I mean, it need not to change as long as it accepts arguments as AirPlane.
Because it will accept any Airplane despite of actual type, flyer, highflyr, fighter, etc.
Also, in a collection:
List<Airplane> plane; // Will take all your planes.
The following example will clear your understanding.
interface Airplane{
parkPlane();
servicePlane();
}
Now your have a fighter plane that implements it, so
public class Fighter implements Airplane {
public void parkPlane(){
// Specific implementations for fighter plane to park
}
public void servicePlane(){
// Specific implementatoins for fighter plane to service.
}
}
The same thing for HighFlyer and other clasess:
public class HighFlyer implements Airplane {
public void parkPlane(){
// Specific implementations for HighFlyer plane to park
}
public void servicePlane(){
// specific implementatoins for HighFlyer plane to service.
}
}
Now think your controller classes using AirPlane several times,
Suppose your Controller class is AirPort like below,
public Class AirPort{
AirPlane plane;
public AirPlane getAirPlane() {
return airPlane;
}
public void setAirPlane(AirPlane airPlane) {
this.airPlane = airPlane;
}
}
here magic comes as Polymorphism makes your code more flexible because,
you may make your new AirPlane type instances as many as you want and you are not changing
code of AirPort class.
you can set AirPlane instance as you like (Thats called dependency Intection too)..
JumboJetPlane // implementing AirPlane interface.
AirBus // implementing AirPlane interface.
Now think of If you create new type of plane, or you remove any type of Plane does it make difference to your AirPort?
No, Because we can say the The AirPort class refers the AirPlane polymorphically.
As far as I understand, the advantage is that, for example, in a airplane combat game, you have to update all airplanes' positions at every loop, but you have several different airplanes. Let's say you have:
MiG-21
Waco 10
Mitsubishi Zero
Eclipse 500
Mirage
You don't want to have to update their movements and positions in separate like this:
Mig21 mig = new Mig21();
mig.move();
Waco waco = new Waco();
waco.move();
Mitsubishi mit = new Mitsubishi();
mit.move();
...
You want to have a superclass that can take any of this subclasses (Airplane) and update all in a loop:
airplaneList.append(new Mig21());
airplaneList.append(new Waco());
airplaneList.append(new Mitsubishi());
...
for(Airplane airplane : airplanesList)
airplane.move()
This makes your code a lot simpler.
You are completely correct that sub-classes are only useful to those who instantiate them. This was summed up well by Rich Hickey:
...any new class is itself an island; unusable by any existing code written by anyone, anywhere. So consider throwing the baby out with the bath water.
It is still possible to use an object which has been instantiated somewhere else. As a trivial example of this, any method which accepts an argument of type "Object" will probably be given an instance of a sub-class.
There is another problem though, which is much more subtle. In general a sub-class (like Jet) will not work in place of a parent class (like Airplane). Assuming that sub-classes are interchangable with parent classes is the cause of a huge number of bugs.
This property of interchangability is known as the Liskov Substitution Principle, and was originally formulated as:
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
In the context of your example, T is the Airplane class, S is the Jet class, x are the Airplane instances and y are the Jet instances.
The "properties" q are the the results of the instances' methods, the contents of their properties, the results of passing them to other operators or methods, etc. We can think of "provable" as meaning "observable"; ie. it doesn't matter if two objects are implemented differently, if there is no difference in their results. Likewise it doesn't matter if two objects will behave differently after an infinite loop, since that code can never be reached.
Defining Jet as a sub-class of Airplane is a trivial matter of syntax: Jet's declaration must contain the extends Airplane tokens and there mustn't be a final token in the declaration of Airplane. It is trivial for the compiler to check that objects obey the rules of sub-classing. However, this doesn't tell us whether Jet is a sub-type of Airplane; ie. whether a Jet can be used in place of an Airplane. Java will allow it, but that doesn't mean it will work.
One way we can make Jet a sub-type of Airplane is to have Jet be an empty class; all of its behaviour comes from Airplane. However, even this trivial solution is problematic: an Airplane and a trivial Jet will behave differently when passed to the instanceof operator. Hence we need to inspect all of the code which uses Airplane to make sure that there are no instanceof calls. Of course, this goes completely against the ideas of encapsulation and modularity; there's no way we can inspect code which may not even exist yet!
Normally we want to sub-class in order to do something differently to the superclass. In this case, we have to make sure that none of these differences is observable to any code using Airplane. This is even more difficult than syntactically checking for instanceof; we need to know what all of that code does.
That's impossible due to Rice's Theorem, hence there's no way to check sub-typing automatically, and hence the amount of bugs it causes.
For these reasons, many see sub-class polymorphism as an anti-pattern. There are other forms of polymorphism which don't suffer these problems though, for example "parameteric polymorphism" (referred to as "generics" in Java).
Liskov Substitution Principle
Comparison between sub-classing and sub-typing
Parameteric polymorphism
Arguments against sub-classing
Rice's theorem
One good example of when polymorphism is useful:
Let us say you have abstract class Animal, which defines methods and such common to all animals, such as makeNoise()
You then could extend it with subclasses such as Dog, Cat, Tiger.
Each of these animals overrides the methods of the abstract class, such as makeNoise(), to make these behaviors specific to their class. This is good because obiously each animal makes a different noise.
Here is one example where polymorphism is a great thing: collections.
Lets say I have an ArrayList<Animal> animals, and it is full of several different animals.
Polymorphism makes this code possible:
for(Animal a: animals)
{
a.makeNoise();
}
Because we know that each subclass has a makeNoise() method, we can trust that this will cause each animal object to call their specific version of makeNoise()
(e.g. the dog barks, the cat meows, the cow moos, all without you ever even having to worry about which animal does what.)
Another advantage is apparent when working with a team on a project. Let's say another developer added several new animals without ever telling you, and you have a collection of animals which now has some of these new animal types (which you dont even know exist!). You can still call the makeNoise() method (or any other method in the animal superclass) and trust that each type of animal will know what to do.
The nice thing about this animal superclass is that you can a extend a superclass and make as many new animal types as you want, without changing ANYTHING in the superclass, or breaking any code.
Remember the golden rule of polymorphism. You can use a subclass anywhere a superclass type object is expected.
For example:
Animal animal = new Dog;
It takes a while to learn to think polymorphically, but once you learn your code will improve a lot.
Polymorphism stems from inheritance. The whole idea is that you have a general base class and more specific derived classes. You can then write code that works with the base class... and polymorphims makes your code not only work with the base class, but all derived classes.
If you decide to have your super class have a method, say getPlaneEngineType(), and you make a new child class "Jet which inherits from Plane". Plane jet = new Jet() will/can still access the superclass's getPlaneEngineType. While you could still write your own getJetEngineType() to basically override the superclass's method with a super call, This means you can write code that will work with ANY "plane", not just with Plane or Jet or BigFlyer.
I don't think that's a good example, since it appears to confuse ontology and polymorphism.
You have to ask yourself, what aspect of the behaviour of a 'Jet' is different from an 'Airplane' that would justify complicating the software to model it with a different sub-type? The book's preview cuts off after one page into the example, but there doesn't seem any rationale to the design. Always ask yourself if there is a difference in behaviour rather than just adding classes to categorise things - usually that's better done with a property value or composing strategies than with sub-classes.
An example (simplified from a major project I lead in the early noughties) would be that an Aeroplane is final but has various properties of abstract types, one of which is the engine. There are various ways of calculating the thrust and fuel use of an engine - for fast jets bi-cubic interpolation table of values of thrust and fuel rate against Mach and throttle (and pressure and humidity sometimes), for Rockets the table method but does not require compensation for stalling the air at the engine intake; for props a simpler parametrised 'bootstrap' equation can be used. So you would have three classes of AbstractAeroEngine - JetEngine, RocketEngine and BootstrapEngine which would have implementations of methods which returned thrust and fuel use rate given a throttle setting and the current Mach number. (you should almost never sub-type a non-abstract type)
Note that the differences between the types of AbstractAeroEngine, although related to the different real world engines, are entirely differences in the how the software calculates the engine's thrust and fuel use - you are not constructing an ontology of classes which describe a view of the real world, but specialising the operations performed in the software to suit specific use cases.
How does using a superclass save me from making extra changes to rest of my code?
As all your engine calculations are polymorphic, it means that when you create an aeroplane, you can bolt on whatever engine thrust calculation suits it. If you find you have to cater for another method of calculating the thrust (as we did, several times) then you can add another sub-type of AeroEngine - as long as the implementation it supplies provides the trust and fuel rate, then the rest of the system doesn't care about the internal differences - the AeroPlane class will still ask its engine for the thrust. The aeroplane only cares that it has an engine which it can use the same way as any other engine, only the creation code has to know the type of the engine to bolt onto it, and the implementation of ScramJetEngine only cares about supersonic jet calculations - the parts of AeroPlane which calculate lift and drag, and the strategy for flying it don't have to change.
Polymorphism is powerful given that when there's a need to change a behavior you can change it by overriding a method.
Your superclass inherits its properties and behaviors to your subclasses extended by it. Thus it is safe to implicitly cast an object whose type is also from its superclass. Those common methods to your subclasses make them useful to implement an API. With that, polymorphism gives you the ability to extend a functionality of your code.
Polymorphism gains properties and all behaviors and interfaces of the super class. So is the behavior of a plane really the same as a jet?
I'm trying to understand whether the answer to the following question is the same in all major OOP languages; and if not, then how do those languages differ.
Suppose I have class A that defines methods act and jump; method act calls method jump. A's subclass B overrides method jump (i.e., the appropriate syntax is used to ensure that whenever jump is called, the implementation in class B is used).
I have object b of class B. I want it to behave exactly as if it was of class A. In other words, I want the jump to be performed using the implementation in A. What are my options in different languages?
For example, can I achieve this with some form of downcasting? Or perhaps by creating a proxy object that knows which methods to call?
I would want to avoid creating a brand new object of class A and carefully setting up the sharing of internal state between a and b because that's obviously not future-proof, and complicated. I would also want to avoid copying the state of b into a brand new object of class A because there might be a lot of data to copy.
UPDATE
I asked this question specifically about Python, but it seems this is impossible to achieve in Python and technically it can be done... kinda..
It appears that apart from technical feasibility, there's a strong argument against doing this from a design perspective. I'm asking about that in a separate question.
The comments reiterated: Prefer composition over inheritance.
Inheritance works well when your subclasses have well defined behavioural differences from their superclass, but you'll frequently hit a point where that model gets awkward or stops making sense. At that point, you need to reconsider your design.
Composition is usually the better solution. Delegating your object's varying behaviour to a different object (or objects) may reduce or eliminate your need for subclassing.
In your case, the behavioural differences between class A and class B could be encapsulated in the Strategy pattern. You could then change the behaviour of class A (and class B, if still required) at the instance level, simply by assigning a new strategy.
The Strategy pattern may require more code in the short run, but it's clean and maintainable. Method swizzling, monkey patching, and all those cool things that allow us to poke around in our specific language implementation are fun, but the potential for unexpected side effects is high and the code tends to be difficult to maintain.
What you are asking is completely unrelated/unsupported by OOP programming.
If you subclass an object A with class B and override its methods, when a concrete instance of B is created then all the overriden/new implementation of the base methods are associated with it (either we talk about Java or C++ with virtual tables etc).
You have instantiated object B.
Why would you expect that you could/would/should be able to call the method of the superclass if you have overriden that method?
You could call it explicitely of course e.g. by calling super inside the method, but you can not do it automatically, and casting will not help you do that either.
I can't imagine why you would want to do that.
If you need to use class A then use class A.
If you need to override its functionality then use its subclass B.
Most programming languages go to some trouble to support dynamic dispatch of virtual functions (the case of calling the overridden method jump in a subclass instead of the parent class's implementation) -- to the degree that working around it or avoiding it is difficult. In general, specialization/polymorphism is a desirable feature -- arguably a goal of OOP in the first place.
Take a look at the Wikipedia article on Virtual Functions, which gives a useful overview of the support for virtual functions in many programming languages. It will give you a place to start when considering a specific language, as well as the trade-offs to weigh when looking at a language where the programmer can control how dispatch behaves (see the section on C++, for example).
So loosely, the answer to your question is, "No, the behavior is not the same in all programming languages." Furthermore, there is no language independent solution. C++ may be your best bet if you need the behavior.
You can actually do this with Python (sort of), with some awful hacks. It requires that you implement something like the wrappers we were discussing in your first Python-specific question, but as a subclass of B. You then need to implement write-proxying as well (the wrapper object shouldn't contain any of the state normally associated with the class hierarchy, it should redirect all attribute access to the underlying instance of B.
But rather than redirecting method lookup to A and then calling the method with the wrapped instance, you'd call the method passing the wrapper object as self. This is legal because the wrapper class is a subclass of B, so the wrapper instance is an instance of the classes whose methods you're calling.
This would be very strange code, requiring you to dynamically generate classes using both IS-A and HAS-A relationships at the same time. It would probably also end up fairly fragile and have bizarre results in a lot of corner cases (you generally can't write 100% perfect wrapper classes in Python exactly because this sort of strange thing is possible).
I'm completely leaving aside weather this is a good idea or not.
My understanding of the Liskov substitution principle is that some property of the base class that is true or some implemented behaviour of the base class, should be true for the derived class as well.
I guess this would mean when a method is defined in a base class, it should never be overrided in the derived class - since then substituting the base class instead of the derived class would give different results. I guess this would also mean, having (non-pure) virtual methods is a bad thing?
I think I might have a wrong understanding of the principle. If I don't, I do not understand why is this principle good practice. Can someone explain this to me? Thanks
Subclasses overriding methods in the base class are totally allowed by the Liskov Substituion Principle.
This might be simplifying it too much, but I remember it as "a subclass should require nothing more and promise nothing less"
If a client is using a superclass ABC with a method something(int i), then the client should be able to substitute any subclass of ABC without problems. Instead of thinking about this in terms of variable types, perhaps think about it in terms of preconditions and postconditions.
If our something() method in the ABC base class above has a relaxed precondition that permits any integer, then all subclasses of ABC must also permit any integer. A subclass GreenABC is not allowed to add an additional precondition to the something() method that requires the parameter to be a positive integer. This would violate the Liskov Substitution Principle (i.e., requiring more). Thus if a client is using subclass BlueABC and passing negative integers to something() the client won't break if we need to switch to GreenABC.
In reverse, if the base ABC class something() method has a postcondition - such as guaranteeing it will never return a value of zero - then all subclasses must also obey that same postcondition or they violate the Liskov Substitution Principle (i.e., promising less).
I hope this helps.
There is one popular example which says if it swims like a duck, quack likes a duck but requires batteries, then it breaks Liskov Substitution Principle.
Put it simply, you have a base Duck class which is being used by someone. Then you add hierarchy by introduction PlasticDuck with same overridden behaviors (like swimming, quacking etc.) as of a Duck but requires batteries to simulate those behaviors. This essentially means that you are introducing an extra pre-condition to the behavior of Sub Class to require batteries to do the same behavior that was earlier done by the Base Duck class without batteries. This might catch the consumer of your Duck class by surprise and might break the functionality built around the expected behavior of Base Duck class.
Here is a good link - http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/
No, it tells that you should be able to use derived class in the same way as its base. There're many ways you can override a method without breaking this. A simple example, GetHashCode() in C# is in base for ALL classes, and still ALL of them can be used as "object" to calculate the hash code. A classic example of breaking the rule, as far as I remember, is derivin Square from Rectangle, since Square can't have both Width and Height - because setting one would change another and thus it's no more conforms to Rectangle rules. You can, however, still have base Shape with .GetSize() since ALL shapes can do this - and thus any derived shape can be substituted and used as Shape.
Overriding breaks Liskov Substitution Principle if you change any behavior defined by a base method. Which means that:
The weakest precondition for a
child method should be not stronger
than for the base method.
A postcondition for the child method
implies a postcondition for the
parent method. Where a postcondition
is formed by: a) all side
effects caused by a method execution and b)
type and value of a returned expression.
From these two requirements you can imply that any new functionality in a child method that does not affect what is expected from a super method does not violate the principle. These conditions allow you to use a subclass instance where a superclass instance is required.
If these rules are not obeyed a class violates LSP. A classical example is the following hierarchy: class Point(x,y), class ColoredPoint(x,y,color) that extends Point(x,y) and overridden method equals(obj) in ColoredPoint that reflects equality by color. Now if one have an instance of Set<Point> he can assume that two points with the same coordinates are equal in this set. Which is not the case with the overridden method equals and, in general, there is just no way to extend an instantiable class and add an aspect used in equals method without breaking LSP.
Thus every time you break this principle you implicitly introduce a potential bug that reveals when invariant for a parent class that is expected by the code is not satisfied. However, in real world often there is no obvious design solution that does not violate LSP, so one can use, for example, #ViolatesLSP class annotation to warn a client that it is not safe to use class instances in a polymorphic set or in any other kind of cases that rely on the Liskov substitution principle.
I think that you're literally correct in the way you describe the principle and only overriding pure virtual, or abstract methods will ensure that you don't violate it.
However, if you look at the principle from a client's point of view, that is, a method that takes a reference to the base class. If this method cannot tell (and certainly does not attempt to and does not need to find out) the class of any instance that is passed in, then you are also not violating the principle. So it may not matter that you override a base class method (some sorts of decorators might do this, calling the base class method in the process).
If a client seems to need to find out the class of an instance passed in, then you're in for a maintenance nightmare, as you should really just be adding new classes as part of your maintenance effort, not modifying an existing routine. (see also OCP)
The original principle:
"What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.".
Barbara Liskov, 1987
The word is behavior. The "preconditions and postconditions" understanding is useful for a good design but is not related to LSP.
Let's check this summary of "preconditions and postconditions" theory:
Don’t implement any stricter validation rules on input parameters than implemented by the parent class.
Apply at the least the same rules to all output parameters as applied by the parent class.
An indication that it has nothing to do with LSP is: what about VOID methods? VOID does not have OUTPUT parameters. How could this rule be applied to VOID methods? How, according to this rule, could we guarantee to be complying with LSP in VOID methods?
LSP refers to Behavior. When a subclass inherits from a superclass and you have to use some trick to make this work, and the result change the behavior of the program you are breaking LSP.
LSP is about behaviour and the clasic example of Square x Rectangle help us to understand. In fact is the example used by Uncle Bob.
The you inherit Square from Rectangle and overrides SetHeight and SetWidth to force Square act as a Square even if it's a rectangle (by inheritance).
When the user calls SetHeight do not expect Width change.... but will change and this change the expected behavior and break LSP.
This is the problem with Virtuals x LSP