14

When you use the concept of polymorphism you create a class hierarchy and using parents reference you call the interface functions without knowing which specific type has the object. This is great. Example:

You have collection of animals and you call on all animals function eat and you don't care if it is a dog eating or a cat. But in the same class hierarchy you have animals that have additional - other than inherited and implemented from class Animal, e.g. makeEggs, getBackFromTheFreezedState and so on. So in some cases in you function you might want to know the specific type to call additional behaviours.

For example, in case it is morning time and if it is just an animal then you call eat, otherwise if it is a human, then call first washHands, getDressed and only then call eat. How to handle this cases? Polymorphism dies. You need to find out the type of the object, which sounds like a code smell. Is there a common approach to handle this cases?

  • 7
    The type of polymorphism you described is called subtyping polymorphism, but it is not the only kind (see Polymorphism). You don't have to create a class hierarchy to do polymorphism (and I'd actually argue that inheritance is not the most common method to achieve subtyping polymorphism, implementing an interface is much more prevalent). – Vincent Savard Feb 19 '18 at 14:29
  • 24
    If you define a Eater interface with the eat() method, then as a client, you do not care that a Human implementing it has to first call washHands() and getDressed(), it's an implementation details of this class. If, as a client, you do care about this fact, then you're most likely not using the correct tool for the job. – Vincent Savard Feb 19 '18 at 14:31
  • 3
    You also have to consider that while in the morning, a human might need to getDressed before they eat, that is not the case for lunch. Depending on your circumstances, washHands();if !dressed then getDressed();[code to actually eat] might be the best way to implement this for a human. Another possibility is what if other things require that washHands and/or getDressed are called? Suppose you have leaveForWork? You may need to structure your program's flow to have it such that it's called long before that anyway. – Duncan X Simpson Feb 19 '18 at 18:12
  • 1
    Keep in mind that checking against the exact type may be a code smell in OOP but it is a very common practice in FP (i.e. use pattern matching to determine the type of a discriminated union and then act on it). – Theodoros Chatzigiannakis Feb 19 '18 at 18:24
  • 3
    Beware school room examples of OO hierarchies like animals. Real programs almost never have such clean taxonomies. E.g., ericlippert.com/2015/04/27/wizards-and-warriors-part-one. Or if you wanna go whole hog and question the entire paradigm: Object-Oriented Programming is Bad. – jpmc26 Feb 20 '18 at 1:33
18

Depends. Unfortunately there is no generic solution. Think about your requirements and try to figure out what these things should do.

For example, you said in the morning different animals do different stuff. How about you introduce a method getUp() or prepareForDay() or something like that. Then you can continue with polymorphism and let each animal execute its morning routine.

If you want to differentiate among animals, then you should not store them indiscriminately in a list.

If nothing else works, then you could try the Visitor Pattern, which is kind-of a hack to allow for kind-of a dynamic dispatching where you can submit a visitor that will receive type-exact callbacks from animals. I would stress however that this should be a last resort if everything else fails.

33

This is a good question and it's the kind of trouble a lot of people when trying to understand how to use OO. I think most developers struggle with this. I wish I could say that most get past it but I'm not sure that's the case. Most developers, in my experience, end up using pseudo-OO property bags.

First, let me be clear. This is not your fault. The way OO is typically taught is highly flawed. The Animal example is the premier offender, IMO. Basically, we say, let's talk about objects, what can they do. An Animal can eat() and it can speak(). Super. Now create some animals and code how they eat and speak. Now you know OO, right?

The problem is that this is coming at OO from the wrong direction. Why are there animals in this program and why do they need to speak and eat?

I have a hard time thinking of a real use for an Animal type. I'm sure it exists but let's discuss something that I think is easier to reason about: a traffic simulation. Assume we want to model traffic in various scenarios. Here are some basic things that we need to have to be able to do that.

Vehicle
Road
Signal

We can go deeper with all kinds of things pedestrians and trains but we'll keep it simple.

Let's consider Vehicle. What capabilities does the vehicle need? It needs to travel on a road. It needs to be able to stop at signals. It needs to be able navigate intersections.

interface Vehicle {
  move(Road road);
  navigate(Road... intersection);
}

This is probably too simple but it's a start. Now. What about all the other things that a vehicle might do? They can turn off of a road and into a ditch. Is that part of the simulation? No. Don't need it. Some cars and buses have hydraulics that allow them to bounce or kneel respectively. Is that part of the simulation? No. Don't need it. Most cars burn gasoline. Some don't. Is the power plant part of the simulation? No. Don't need it. Wheel size? Don't need it. GPS navigation? Infotainment system? Don't need em.

You only need to define behaviors that you are going to use. To that end, I think it's often better to build OO interfaces from the code that interacts with them. You start with an empty interface and then start writing the code that calls the non-existent methods. That's how you know what methods you need on your interface. Then once you've done that, you go and start defining classes that implement these behaviors. Behaviors that are not used are irrelevant and do not need to be defined.

The whole point of OO is that you can add new implementations of these interfaces later without changing the calling code. The only way that works is if the needs of the calling code determines what goes in the interface. There is no way to define all the behaviors of all the possible things that could be thought up later.

  • 13
    This is a good answer. "To that end, I think it's often better to build OO interfaces from the code that interacts with them." Absolutely, and I'd argue it's the only way. You can't know the public contract of an interface only through the implementation, it's always defined from the perspective of its clients. (And as a side note, this is what TDD is actually about.) – Vincent Savard Feb 19 '18 at 17:22
  • @VincentSavard "I'd argue it's the only way." You are right. I guess the reason I didn't make it that absolute is that once you have the idea, you can kind of flesh out the interface and then refine it this way. Ultimately, when you get down to brass tacks, it's the only thing that matters. – JimmyJames Feb 19 '18 at 22:14
  • @jpmc26 Perhaps a little strongly worded. I'm not sure I agree that it's rare to implement this. I'm not sure how interfaces can be useful if you aren't using them in this way aside from marker interfaces which I think are a terrible idea. – JimmyJames Feb 20 '18 at 14:46
9

TL;DR:

Think about an abstraction and methods that apply to all subclasses and cover everything you need.

Let's first stay with your eat() example.

It's a property of being a human that, as a precondition to eating, humans want to wash their hands and get dressed before eating. If you want someone to come to you to eat breakfast with you, you don't tell them to wash their hands and get dressed, they do it on their own when you invite them, or they answer "No, I can't come over, I haven't washed my hands, and I'm not yet dressed".

Back to software:

As a Human instance won't eat without the preconditions, I'd have the Human's eat() method do washHands() and getDressed() if that hasn't been done. It shouldn't be your job as the eat() caller to know about that peculiarity. The stubborn-human's alternative would be to throw an exception ("I'm not prepared to eat!") if the preconditions aren't met, leaving you frustrated, but at least informed that eating didn't work.

What about makeEggs()?

I'd recommend to change your way of thinking. You probably want to execute the scheduled morning duties of all the beings. Again, as the caller it shouldn't be your job to know what their duties are. So I'd recommend a doMorningDuties() method that all classes implement.

  • I agree with this answer. Narek is right about the code smell. It is the interface design that is smelly, so fix that and your good. – Jonathan van de Veen Feb 20 '18 at 8:24
  • What this answer describes is usually referred to as the Liskov Substitution Principle. – Philipp Feb 20 '18 at 9:36
2

The answer is quite simple.

How to handle objects that can do more than you expect?

You do not need to handle it because it would serve no purpose. An interface is usually designed depending on how it's going to be used. If your interface does not define washing hands, then you do not care about it as the interface caller; if you did you would have designed it differently.

For example, in case it is morning time and if it is just an animal then you call eat, otherwise if it is a human, then call first washHands, getDressed and only then call eat. How to handle this cases?

For example, in pseudocode:

interface IEater { void Eat(); }
interface IMorningRoutinePerformer { void DoMorningRoutine(); }
interface IAnimal : IEater, IMorningPerformer;
interface IHuman : IEater, IMorningPerformer; 
{
  void WashHands();
  void GetDressed();
}

void MorningTime()
{
   IList<IMorningRoutinePerformer> items = Service.GetMorningPerformers();
   foreach(item in items) { item.DoMorningRoutine(); }
}

Now you implement IMorningPerformer for Animal to just perform eating, and for Human you also implement it to wash hands and get dressed. Caller of your MorningTime method could care less if it's human or an animal. All it wants is the morning routine performed, which each object does admirably thanks to OO.

Polymorphism dies.

Or does it?

You need to find out the type of the object

Why are assuming that? I think this could be a wrong assumption.

Is there a common approach to handle this cases?

Yes, usually it's solved with carefully designed class or interface hierarchy. Note that in the example above there is nothing that contradicts your example as you've given it, yet, you probably will feel dissatisfied, because you've made some more assumptions that you did not write in the question as of the moment of writing, and these assumptions are probably violated.

It is possible to go to a rabbit hole by you tightening your assumptions and me modifying the answer to still satisfy them, but I do not think that would be useful.

Designing good class hierarchies is difficult and it requires a lot of insight into your business domain. For complex domains one goes over two, three or even more iterations, as they refine their understanding of how different entities in their business domain interact, until they arrive at an adequate model.

That's where simplistic animal examples are lacking. We want to teach simple, but the problem we are trying to solve is not obvious until you go deeper, that is have more complex considerations and domains.

protected by gnat Feb 20 '18 at 14:04

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.